У меня есть класс под названием Collection
который хранит объекты того же типа. Collection
реализует интерфейсы массивов: Iterator
, ArrayAccess
, SeekableIterator
и Countable
.
Я хотел бы передать объект Collection
в качестве аргумента array_map
функции array_map
. Но это не удается с ошибкой
PHP Предупреждение: array_map (): Аргумент # 2 должен быть массивом
Могу ли я достичь этого, реализуя другие / дополнительные интерфейсы, чтобы объекты Collection
рассматривались как массивы?
Функция array_map()
не поддерживает Traversable
качестве аргумента массива, поэтому вам нужно будет выполнить шаг преобразования:
array_map($fn, iterator_to_array($myCollection));
Помимо повторной обработки коллекции дважды, она также дает массив, который впоследствии не будет использоваться.
Другой способ – написать собственную функцию карты:
function map(callable $fn) { $result = array(); foreach ($this as $item) { $result[] = $fn($item); } return $result; }
Обновить
Судя по вашему делу, кажется, что вас даже не интересует результат операции с картой; поэтому имеет смысл использовать iterator_apply()
.
iterator_apply($myCollection, function($obj) { $obj->method1(); $obj->method2(); return true; });
array_map
хочет, как следует из названия, массивов . В конце концов, он не называется iterator_map
. 😉
Помимо iterator_to_array()
, который создает потенциально большой временный массив, нет никакого трюка, чтобы сделать итерационные объекты работать с array_map
.
Функциональная библиотека PHP имеет реализацию map
которая работает в любой итеративной коллекции.
Я придумал следующее решение:
//lets say you have this iterator $iterator = new ArrayIterator(array(1, 2, 3)); //and want to append the callback output to the following variable $out = []; //use iterator to apply the callback to every element of the iterator iterator_apply( $iterator, function($iterator, &$out) { $current = $iterator->current(); $out[] = $current*2; return true; }, array($iterator, &$out) //arguments for the callback ); print_r($out);
Таким образом, вы можете сгенерировать массив без повторения дважды, как вам хотелось бы с таким подходом, как:
$iterator = new ArrayIterator(array(1,2,3)); $array = iterator_to_array($iterator); //first iteration $output = array_map(function() {}, $array); //second iteration
Удачи!
Если вы не заинтересованы в создании нового массива, который является функцией, сопоставленной с исходным массивом, вы можете просто использовать цикл foreach (потому что вы реализуете Iterator
).
foreach($item in $myCollection) { $item->method1(); $item->method2(); }
если вы действительно хотите использовать карту, то я думаю, вам придется реализовать свои собственные. Я бы предложил сделать его методом в коллекции, например:
$mutatedCollection = $myCollection->map(function($item) { /* do some stuff to $item */ return $item; });
Я хотел бы спросить себя, действительно ли вы хотите использовать map
или вы действительно просто означаете foreach