예제 #1
0
 /**
  * Sorts the elements in an array by comparing return values from a specified method being called on each element.
  *
  * For example, if you had an array of UserClass objects and UserClass had a public method named `numPosts` that
  * would return an integer value, you could sort the users by the number of posts they've made by calling this
  * method with "numPosts" as the value of `$onMethodName` parameter.
  *
  * If you want to pass any custom arguments to the method that the array needs to be sorted on, just add them after
  * the comparator parameter when calling this method and the custom arguments will be passed to that method in the
  * same order.
  *
  * The method on which the array needs to be sorted can be static and, in this case, every element for which that
  * method is called is passed to that method as the first argument, in front of any custom arguments if they are
  * used.
  *
  * You can use your own comparator for the comparison of return values for the elements in the array, but the
  * default comparators, such as `CComparator::ORDER_ASC` and `CComparator::ORDER_DESC`, have got you covered when
  * sorting by scalar values, such as `string`, `int`, `float`, and `bool` in the ascending or descending order
  * respectively. And the default comparators are smart enough to know how to compare objects of those classes that
  * conform to the IEqualityAndOrder interface (static or not), including CArray and CMap. See the
  * [CComparator](CComparator.html) class for more on this.
  *
  * @param  array $array The array to be sorted.
  * @param  string $onMethodName The name of the method on which the elements are to be sorted.
  * @param  callable $comparator **OPTIONAL. Default is** `CComparator::ORDER_ASC`. The function or method to be
  * used for the comparison of any two return values. If this parameter is provided, the comparator should take two
  * parameters, which are the return values for the two elements being compared, and return `-1` if the first
  * element needs to go before the second element in the sorted array, `1` if the other way around, and `0` if the
  * two elements are considered equal based on the return values.
  *
  * @return void
  *
  * @link   CComparator.html CComparator
  */
 public static function sortOn($array, $onMethodName, $comparator = CComparator::ORDER_ASC)
 {
     assert('is_carray($array) && is_cstring($onMethodName) && is_callable($comparator)', vs(isset($this), get_defined_vars()));
     $array = splarray($array);
     static $s_methodArgsStartPos = 3;
     $methodArgs = func_num_args() == $s_methodArgsStartPos ? [] : array_slice(func_get_args(), $s_methodArgsStartPos);
     $useComparator = function ($element0, $element1) use($onMethodName, $comparator, $methodArgs) {
         $className;
         $typeIsNonScalar = phred_classify_duo($element0, $element1, $className);
         if (CDebug::isDebugModeOn()) {
             // Except for a few special cases, any two elements being compared must be objects of the same
             // class.
             assert('$typeIsNonScalar', vs(isset($this), get_defined_vars()));
             $className0;
             $className1;
             phred_classify($element0, $className0);
             phred_classify($element1, $className1);
             assert('CString::equals($className0, $className1)', vs(isset($this), get_defined_vars()));
         }
         $reflClass = new ReflectionClass($className);
         assert('$reflClass->hasMethod($onMethodName)', vs(isset($this), get_defined_vars()));
         $reflMethod = $reflClass->getMethod($onMethodName);
         assert('$reflMethod->isPublic()', vs(isset($this), get_defined_vars()));
         $methodInvokeRes0;
         $methodInvokeRes1;
         if (!$reflMethod->isStatic()) {
             if (empty($methodArgs)) {
                 $methodInvokeRes0 = $reflMethod->invoke($element0);
                 $methodInvokeRes1 = $reflMethod->invoke($element1);
             } else {
                 $methodInvokeRes0 = $reflMethod->invokeArgs($element0, $methodArgs);
                 $methodInvokeRes1 = $reflMethod->invokeArgs($element1, $methodArgs);
             }
         } else {
             if (empty($methodArgs)) {
                 $methodInvokeRes0 = $reflMethod->invoke(null, $element0);
                 $methodInvokeRes1 = $reflMethod->invoke(null, $element1);
             } else {
                 $methodInvokeRes0 = $reflMethod->invokeArgs(null, $element0, $methodArgs);
                 $methodInvokeRes1 = $reflMethod->invokeArgs(null, $element1, $methodArgs);
             }
         }
         return call_user_func($comparator, $methodInvokeRes0, $methodInvokeRes1);
     };
     self::sort($array, $useComparator);
 }
예제 #2
0
/**
 * @ignore
 */
function phred_classify_duo($value0, $value1, &$className)
{
    if (!is_object($value0) || !is_object($value1)) {
        return phred_classify($value0, $className);
    }
    if ($value0 instanceof CArrayObject && $value1 instanceof CArrayObject) {
        $className = "CArrayObject";
        return true;
    }
    if ($value0 instanceof CMapObject && $value1 instanceof CMapObject) {
        $className = "CMapObject";
        return true;
    }
    return phred_classify($value0, $className);
}