PHP iterator_apply() 函数
不知道大家会不会经常遇到这样的需求,就是为迭代器/生成器中的每一个元素应用一个函数,然后返回应用函数后的新的迭代器?
就像 array_map() 函数一样,例如要将数组 [1,2,5,8] 中的每个元素都平方一下,可以使用下面的语句
<?php $func = function($value) { return $value * $value; }; print_r(array_map($func, [1,2,5,8]));
就目前所学的知识,如何为迭代器中的每一个元素应用一个函数然后又返回一个迭代器呢 ? 你会怎么做呢 ?
我想,最容易想到的方法,就是使用 foreach 迭代初始的迭代器,然后创建一个新的迭代器,就像下面这样
<?php function count_to_ten() { foreach (range(0,10) as $v) { yield $v; } } function iterator_pow($iterator) { foreach($iterator as $v ) { yield $v * $v; } } $nums = iterator_to_array(iterator_pow(count_to_ten())); print_r($nums);
运行结果如下
Array
(
[0] => 0
[1] => 1
[2] => 4
[3] => 9
[4] => 16
[5] => 25
[6] => 36
[7] => 49
[8] => 64
[9] => 81
[10] => 100
)
因为类似于 array_map() 函数这样的功能如此常见,因此 PHP 在 5.1.0 中提供了 iterator_apply() 函数用于为一个迭代器中的每一个元素应用一个函数,然后返回一个新的迭代器
PHP iterator_apply() 函数
iterator_apply() 函数为迭代器中每个元素调用一个用户自定义函数。该函数的原型如下
int iterator_apply ( Traversable $iterator , callable $function [, array $args ] )
你是不是很疑惑,为什么迭代器返回的是一个整型而不是一个新的迭代器 ?
等等,我发现这个章节的思维错了,因为 iterator_apply() 对标的是 array_walk() 函数,并不是 array_map() 函数
这个函数的返回的整型用于表示已经应用函数的元素个数。一般情况下,这个值和 iterator_count() 是相等的。
| 参数 | 说明 |
|---|---|
| $iterator | 需要循环迭代的迭代器或生成器 |
| $function | 迭代到每个元素时的调用的回调函数,为了遍历 iterator 这个函数必须返回 TRUE |
| $args | 传递到回调函数的参数 |
回到返回值上来,为什么说一般情况下 iterator_apply() 的返回和 iterator_count() 是相等的呢?
这是因为,如果 $function 如果返回 FALSE ,那么就会停止迭代,直接导致剩余的元素没有应用这个函数了。
范例 一
iterator_apply() 函数的简单使用
function print_caps(Iterator $iterator) { echo strtoupper($iterator->current()) . "\n"; return TRUE; } $it = new ArrayIterator(array("Apples", "Bananas", "Cherries")); iterator_apply($it, "print_caps", array($it));
运行结果如下
APPLES BANANAS CHERRIES
范例三
我突然间意思到一个问题,iterator_apply() 对标的并不是数组的 array_map() 函数,而是 array_walk() 函数。
因为 iterator_apply() 并不会改变原来的迭代器,也不会创建新的迭代器。而且调用完了之后迭代器或者生成器就不再可用了。
大型翻车现场
我们写一个范例求证下
<?php function count_to_ten() { foreach (range(0,10) as $v) { yield $v; } } function mpow($it) { $v = $it->current(); $ret = $v * $v; echo $ret, " "; return TRUE; } $gen = count_to_ten(); var_dump($gen); iterator_apply($gen, "mpow", array($gen)); echo "\n"; var_dump($gen); print_r(iterator_to_array($gen));
运行结果如下
[yufei@www.twle.cn helloworld]$ php d.php
object(Generator)#1 (0) {
}
0 1 4 9 16 25 36 49 64 81 100
object(Generator)#1 (0) {
}
Fatal error: Uncaught Exception: Cannot traverse an already closed generator in /Users/yufei/workspace/php/helloworld/demo.php:29
Stack trace:
#0 /Users/php/workspace/php/helloworld/demo.php(29): iterator_to_array(Object(Generator))
#1 {main}
thrown in /Users/yufei/workspace/php/helloworld/demo.php on line 29