Подтвердить что ты не робот

Функция usort в классе

У меня есть функция, которая сортирует данные в многомерном массиве, как показано ниже:

<?php  
$data = array();  
$data[] = array("name" => "James");  
$data[] = array("name" => "andrew");  
$data[] = array("name" => "Fred");  

function cmp($a, $b)  
{  
    return strcasecmp($a["name"], $b["name"]);  
}  

usort($data, "cmp");  

var_dump($data);  
?>  

Когда я запускаю это, он работает как ожидалось, возвращая данные, упорядоченные по имени, по возрастанию. Однако мне нужно использовать это в классе.

<?php
class myClass  
{  
    function getData()  
    {  
        // gets all data
        $this -> changeOrder($data);
    }  

    function changeOrder(&$data)  
    {  
         usort($data, "order_new");
    }

    function order_new($a, $b)  
    {  
        return strcasecmp($a["name"], $b["name"]);  
    }
}
?>

Когда я использую это, я получаю следующее предупреждение: Предупреждение: usort() ожидает, что параметр 2 будет действительным обратным вызовом, функция "order_new" не найдена или неверное имя функции.

Когда я помещаю функцию order_new в функцию changeOrder, она работает нормально, но у меня проблемы с Неустранимая ошибка: не удается переопределить order_new(), поэтому я не могу ее использовать. Любые предложения?

4b9b3361

Ответ 1

order_new - метод класса, а не глобальная функция. Как показано в PHP-руководстве, вы можете использовать в этом случае

usort($data, array($this, "order_new")); 

или объявить order_new static и использовать

usort($data, array("myClass", "order_new")); 

Ответ 2

Изменить на usort($data, array($this, "order_new"));

Ответ 3

 usort($data, array($this,"order_new"));

- это то, что вы хотите, когда ссылаетесь на функцию в вашем экземпляре класса. См. callable

Метод экземпляра объекта передается как массив, содержащий объект с индексом 0 и имя метода в индексе 1.

Ответ 4

Следует учитывать, что если переменная передается в ваш метод по ссылке, функция usort(), как представляется, выполняется в контексте ссылочной переменной, а не в вашем текущем методе. Поэтому вам необходимо предоставить полное пространство имен в вашей ссылке на класс следующим образом:

usort($data, ['My\NameSpace\MyClass', 'order_new']); 

Ответ 5

// If order_new is a NORMAL function 
usort($data, [$this, 'order_new']);      // self ref object, function name  

// If order_new is a STATIC function 
usort($data, [__CLASS__, 'order_new']);  // string, function name 

Ответ 6

Я знаю, что это старый поток, но сегодня я столкнулся с другим примером, который может выиграть от другого подхода. У меня был случай, когда я хотел использовать конкретный ключ, чтобы я мог абстрагироваться от фактической функции поддержки. Это привело к поиску версии с использованием функции-обертки для возврата анонимной функции с использованием командного слова "use" для указания имени ключа, используемого для сортировки в моем классе. (в моем случае это ключ в свойстве в [вложенном] классе, который присваивается одному из свойств класса, в котором я выполняю сортировку, то есть я сортирую экземпляры на основе свойства в экземпляре "размеры" присваивается свойство "элементов" и хочет иметь возможность сортировать их по ширине, высоте, длине или весу, например). Затем, чтобы получить свою функцию для обратного вызова, вы просто вызываете эту функцию-обертку с помощью имени ключа, которое вы хотите использовать для сортировки результата:

/**
 * list of items
 *
 * @var Item[]
 */
public $items;

/**
 * @param string $key
 * @return \Closure
 */
private static function keySort($key) {
    return function ($ia, $ib) use ($key) {
        if($ia->dimensions->$key == $ib->dimensions->$key) return 0;
        return ($ia->dimensions->$key < $ib->dimensions->$key) ? -1 : 1;
    };
}

/**
 * return the list of items in the items array sorted by the value
 *   of the property specified by $key
 *
 * @param string $key
 * @return Item[]
 * @throws \Exception
 */
public function sortItemsByKey($key)
{
    if(in_array($key, array( 'width', 'length', 'height', 'weight', ))) {
        return usort($this->items, static::keySort($key));
    } else
        throw new \Exception(__METHOD__ . ' invalid sort key!');
}

Это позволяет мне называть его локальным, используя либо static:: или self:: (возможно, я мог бы даже обернуть его как нестационарную функцию в этом случае, так как единственное, что меня беспокоит, - это вызов, но функция возвращена) Еще одно преимущество, которое я вскоре обнаружил, - это мой размерный объект, который также имеет некоторые "рассчитанные" поля, такие как обхват, объем и размерный вес. Но одна проблема заключается в том, что размерный вес варьируется в зависимости от того, отправляете ли вы товар внутри страны или на международном уровне, поэтому мне нужно сообщить свою функцию "calculateDimensionalWeight", если она должна использовать значение для международной доставки или нет. Ну, используя этот метод, я могу это сделать, просто передав дополнительный параметр функции-оболочки и добавив дополнительный параметр к переменным использования. Так как мне также необходимо убедиться, что эти значения были рассчитаны до выполнения каких-либо сравнений, я могу вызвать это в моей функции на основе ключа:

/**
 * @param string $key
 * @param bool $intl // only used for dimensional weight
 * @return \Closure
 */
private static function keySort($key,$intl=false) {
    return function ($ia, $ib) use ($key,$intl) {
        switch($key) {
            case 'girth':
                $ia->dimensions->calculateGirth();
                $ib->dimensions->calculateGirth();
                break;
            case 'dimweight':
                $ia->dimensions->calculateDimensionalWeight($intl);
                $ib->dimensions->calculateDimensionalWeight($intl);
                break;
            case 'volume':
                $ia->dimensions->calculateVolume();
                $ib->dimensions->calculateVolume();
                break;
        }
        if($ia->dimensions->$key == $ib->dimensions->$key) return 0;
        return ($ia->dimensions->$key < $ib->dimensions->$key) ? -1 : 1;
    };
}

/**
 * return the list of items in the items array sorted by the value
 *
 * @param string $key
 * @param bool $intl  (only used for dimensional weight sorts on international shipments)
 * @return Item[]
 * @throws \Exception
 */
public function sortItemsByKey($key,$intl=false)
{
    if(in_array($key, array('value','collect', 'width', 'length', 'height', 'weight', 'girth', 'dimweight', 'volume'))) {
        return usort($this->items, static::keySort($key,$intl));
    } else
        throw new \Exception(__METHOD__ . ' invalid sort key!');
}

ПРИМЕЧАНИЕ: вычисление значений таким образом создает накладные расходы, так как все, кроме первого и последнего элементов в любом списке, будут технически вычисляться дважды, что является избыточным, но в этом случае мои списки не длинны, а в некоторых случаях мне нужно сравнить два при выполнении сортировки по ячейкам, поэтому он все же предпочтительнее. Для больших наборов данных было бы разумнее предварительно вычислять значения, внешние по отношению к методу сортировки.