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