Один из шаблонов, с которыми я часто сталкиваюсь при разработке, пытается собрать значение столбца / атрибута из коллекции объектов в массив. Например:
$ids = array(); foreach ($documents as $document) { $ids[] = $document->name; }
Я единственный, кто сталкивается с этим? И есть ли у PHP способ решить это в меньшем количестве строк? Я посмотрел, но ничего не нашел.
Поскольку я использую структуру MVC, у меня есть доступ к классу BaseUtil, который содержит общие функции, которые действительно не подходят ни в каких конкретных классах. Одним из решений, предложенным сотрудником, является:
class BaseUtil { public static function collect($collection, $property) { $values = array(); foreach ($collection as $item) { $values[] = $item->{$property}; } return $values; } }
Тогда я могу просто сделать:
$ids = BaseUtil::collect($documents, 'name');
Не слишком потертый. У кого-нибудь есть другие идеи? И я схожу с ума или это похоже на проблему, которую PHP должен был решить давно?
Вы можете использовать функцию array_map () для этой цели:
function getName($obj) { return $obj->name; } $documentsName = array_map("getName", $documents);
Вы можете также рассмотреть функцию create_function () для лямбда-функций, если вы не хотите создавать функцию getName () в глобальном пространстве имен.
В PHP 5.3 вы можете даже сделать:
$documentsName = array_map(function ($obj) { return $obj->name; }, $documents);
Вы можете сделать это легко с uuzo goodies
$names = array_map(Functions::extract()->name, $documents);
или с массивами (из узе-лайтов)
$names = Arrays::map($documents, Functions::extract()->name);
Вы даже можете извлечь вложенные поля вызовов методов или доступа к массиву и т. Д .:
$names = Arrays::map($documents, Functions::extract()->getAuthor()->roles[0]);
Выезд: http://ouzo.readthedocs.org/ru/latest/utils/functions.html#extract
См. Также функциональное программирование с ouzo (я не могу опубликовать ссылку).
другой подход заключается в использовании «богатых» объектов массива, подобных тем, которые найдены на других языках
например
class Ary extends ArrayObject { function pluck($key) { $a = array(); foreach($this as $sub) $a[] = $sub[$key]; return new self($a); } function join($delim = ',') { return implode($delim, (array) $this); } static function init($ary) { return new self($ary); } } echo Ary::init(array( array('foo', 'bar'), array('baz', 'quux') ))->pluck(1)->join();
Одной из слабых сторон PHP как языка является то, что это не очень выразительно.
Если на таких языках, как Ruby или Perl, вы, вероятно, можете получить эти данные с помощью одной строки кода, вам обычно нужны небольшие алгоритмы, подобные тому, который вы опубликовали, чтобы получить желаемые результаты.
Я придерживаюсь того, что у вас есть, но вот еще один подход только для этого.
class BaseUtil { public static function collect($collection, $property) { array_walk( $collection, array( __CLASS__, 'reduceObject' ), $property ); return $collection; } public static function reduceObject( &$object, $index, $property ) { $object = $object->{$property}; } }
Спасибо за введение, ребята. Думаю, я просто воспользуюсь решением моего коллеги:
class BaseUtil { public static function collect($collection, $property) { $values = array(); foreach ($collection as $item) { $values[] = $item->{$property}; } return $values; } }
Загрузка коллекции Magento и повторение цикла в этой коллекции, чтобы вы могли добавить нужные значения в массив, это неэффективно. Соответствующий способ сделать это – использовать метод getColumnValues (). Этот метод даст вам массив значений, указав имя столбца.
Вот подходящий способ сделать это.
$collection =Mage::getModel('your/object')->getCollection() ->addFieldToSelect('customer_id'); $yourArray = $collection->getColumnValues('customer_id');
Это даст вам массив со всеми выбранными вами значениями customer_id.