Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

array_map on collection with array interfaces?

I have a class called Collection which stores objects of same type. Collection implements array interfaces: Iterator, ArrayAccess, SeekableIterator, and Countable.

I'd like to pass a Collection object as the array argument to the array_map function. But this fails with the error

PHP Warning: array_map(): Argument #2 should be an array

Can I achieve this by implementing other/more interfaces, so that Collection objects are seen as arrays?

like image 872
f1ames Avatar asked Apr 29 '13 07:04

f1ames


3 Answers

The array_map() function doesn't support a Traversable as its array argument, so you would have to perform a conversion step:

array_map($fn, iterator_to_array($myCollection)); 

Besides iterating over the collection twice, it also yield an array that will not be used afterwards.

Another way is to write your own map function:

function map(callable $fn) {     $result = array();      foreach ($this as $item) {         $result[] = $fn($item);     }      return $result; } 

Update

Judging by your use-case it seems that you're not even interested in the result of the map operation; therefore it makes more sense to use iterator_apply().

iterator_apply($myCollection, function($obj) {     $obj->method1();     $obj->method2();      return true; }); 
like image 101
Ja͢ck Avatar answered Oct 04 '22 04:10

Ja͢ck


array_map wants, as the name suggests, arrays. It's not called iterator_map after all. ;)

Apart from iterator_to_array(), which produces a potentially large temporary array, there's no trick to make iterable objects work with array_map.

The Functional PHP library has a map implementation which works on any iterable collection.

like image 37
deceze Avatar answered Oct 04 '22 03:10

deceze


If you're not interested in creating a new array that is a function mapped over the original array, you could just use a foreach loop (because you implement Iterator).

foreach($item in $myCollection) {
    $item->method1();
    $item->method2();
}

if you actually want to use map, then I think you'll have to implement your own. I would suggest making it a method on Collection, eg:

$mutatedCollection = $myCollection->map(function($item) { 
    /* do some stuff to $item */
    return $item;
});

I would ask yourself if you really want to use map or do you really just mean foreach

like image 26
Chris M Avatar answered Oct 04 '22 04:10

Chris M