У меня есть функция, которая сортирует данные в многомерном массиве, как показано ниже:
<?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"]); } } ?>
Когда я использую это, я получаю следующее предупреждение: Warning: usort () ожидает, что параметр 2 будет действительным обратным вызовом, функция «order_new» не найдена или неверное имя функции.
Когда я помещаю функцию order_new в функцию changeOrder, она работает нормально, но у меня проблемы с Fatal error: не удается переопределить order_new () , поэтому я не могу это использовать. Какие-либо предложения?
order_new – метод класса, а не глобальная функция. Как предлагает PHP-Manual , вы можете использовать в этом случае
usort($data, array($this, "order_new"));
или объявить order_new статическим и использовать
usort($data, array("myClass", "order_new"));
Изменить на usort($data, array($this, "order_new"));
usort($data, array($this,"order_new"));
это то, что вы хотите, когда ссылаетесь на функцию в вашем экземпляре класса. См.
Метод объекта-объекта передается как массив, содержащий объект с индексом 0 и имя метода в индексе 1.
Следует учитывать, что если переменная передается в ваш метод по ссылке, функция usort (), как представляется, выполняется в контексте ссылочной переменной, а не в вашем текущем методе. Поэтому вам необходимо предоставить полное пространство имен в вашей ссылке на класс следующим образом:
usort($data, ['My\NameSpace\MyClass', 'order_new']);
// 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
Я знаю, что это старый поток, но сегодня я столкнулся с другим примером, который может выиграть от другого подхода. У меня был случай, когда я хотел использовать конкретный ключ, чтобы я мог абстрагироваться от фактической функции поддержки. Это привело к поиску версии с использованием функции-обертки для возврата анонимной функции с использованием командного слова «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!'); }
ПРИМЕЧАНИЕ: вычисление значений таким образом создает накладные расходы, поскольку все, кроме первого и последнего элементов в любом списке, будут технически вычисляться дважды, что является избыточным, но в этом случае мои списки не длинны, а в некоторых случаях мне нужно сравнить два элемента при выполнении bin-sorting, так что это все же предпочтительнее. Для больших наборов данных было бы разумнее предварительно вычислять значения, внешние по отношению к методу сортировки.