php的迭代器、生成器(Generator、yield)
作者:bin一、迭代器
迭代是指反复执行一个过程,每执行一次叫做迭代一次。比如普通的遍历便是迭代
php提供了同一的迭代器接口Iterator
interface Iterator extends Traversable { // 返回当前的元素 abstract public mixed current(void) // 返回当前元素的键 abstract public scalar key(void) // 向下移动到下一个元素 abstract public void next(void) // 返回到迭代器的第一个元素 abstract public void rewind(void) // 检查当前位置是否有效 abstract public boolean valid(void) }
通过实现Iterator接口,我们可以自行决定如何遍历对象:
myIterator extends Iterator{ public $one = 1; public $tow = 2; public $thr = 3; } $test = new myIterator() foreach($test as $key => $value) { echo "\n"; var_dump($key, $value); }
当我们使用foreach遍历迭代器时,其实内部执行的顺序是:
重置->末尾?->返回当前值
->下一个->末尾?->返回当前值
->下一个->….
rewind()->valid()->current()
->next()->valid()->current()
->next->….
二、yeild和生成器
相比较迭代器,生成器提供了一种更容易的方法来实现简单的对象迭代,性能开销和复杂性都大大降低。
借用鸟叔的代码:
function xrange($start, $limit, $step = 1) { for ($i = $start, $j = 0; $i <= $limit; $i += $step, $j++) { // 给予键值 yield $j => $i; } } $xrange = xrange(1, 10, 2); foreach ($xrange as $key => $value) { echo $key . ' => ' . $value . "\n"; }
生成器并不是一个普通的函数,他会在执行到yeild时暂停一次,再执行一次函数,就会走到下一个yield。
实际上生成器函数返回的是一个Generator对象,这个对象不能通过new实例化,并且实现了Iterator接口。
Generator implements Iterator { public mixed current(void) public mixed key(void) public void next(void) public void rewind(void) // 向生成器传入一个值 public mixed send(mixed $value) public void throw(Exception $exception) public bool valid(void) // 序列化回调 public void __wakeup(void) }
可以看到生成器除了继承迭代器的方法,还多了一个send函数,用来向生成器传入一个参数,并且当作yield表达式多结果
function paser(){ echo yield . '111'. "11\n"; echo yield "2222\n"; } $one = paser(); $one->send('1nihao'); $one->send('2nihao');
输出结果
第一行因为是字符串拼接,所以将yield替换,然后拼接输出
第二行因为是定义,所以”2222\n”被替换为2nihao了
1nihao11111 2nihao