29

我有一个名为的类Collection,它存储相同类型的对象。 Collection实现数组接口:IteratorArrayAccessSeekableIteratorCountable.

我想将一个Collection对象作为数组参数传递给array_map函数。但这失败并出现错误

PHP 警告:array_map():参数 #2 应该是一个数组

我可以通过实现其他/更多接口来实现这一点,以便将Collection对象视为数组吗?

4

5 回答 5

29

array_map()函数不支持 aTraversable作为其数组参数,因此您必须执行转换步骤:

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;
});
于 2013-04-29T08:33:59.720 回答
9

array_map顾名思义,想要数组iterator_map毕竟不叫。;)

除了iterator_to_array()会产生一个可能很大的临时数组之外,没有任何技巧可以让可迭代对象与array_map.

函数式 PHP库有一个map适用于任何可迭代集合的实现。

于 2013-04-29T08:31:40.593 回答
4

如果您对创建一个映射在原始数组上的函数的新数组Iterator感兴趣,则可以只使用 foreach 循环(因为您实现了)。

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

如果你真的想使用地图,那么我认为你必须实现自己的。我建议将其作为 Collection 上的一种方法,例如:

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

我会问自己,您是否真的想使用map,或者您真的只是想说foreach

于 2015-03-05T22:15:31.270 回答
3

我想出了以下解决方案:

//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

祝你好运!

于 2013-12-23T16:08:25.700 回答
1

我只是偶然发现了这个问题,我设法将集合转换为一个数组以使其工作:

array_map($cb, (array) $collection);

免责声明对于最初的问题,这可能不是一个合适的选择,但我在寻找解决问题时发现了这个问题,我用这个解决方案解决了这个问题。我建议在可能/可行的情况下使用自定义迭代器映射。

另一种选择是做这样的事情:

foreach($collection as &$item) {
    $item = $cb($item);
}

这将改变基础集合。

编辑:

有人指出,强制转换为数组可能会产生不必要的副作用。最好向您的集合添加一个方法以从迭代器返回数组并遍历它,或者添加一个map接受回调并在底层迭代器上运行循环的方法。

于 2018-09-16T19:13:29.767 回答