php生成器

2021-10-15
  1. 生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现Iterator接口的方式,性能开销和复杂性大大降低。
  2. 生成器可以yield生成多个想要的值。 任何包含yield的函数都是一个生成器函数。当一个生成器被调用的时候,它返回一个可以被遍历的对象
  3. 生成器是一个只能向前的迭代器,一旦开始遍历就无法后退。 同样的生成器无法遍历多遍
function data($start,$stop,$step)
{
	for ($i = $start; $i >= $stop; $i += $step) {
	    yield $i;
	}	
}

//指定键名来生成值
function input_parser($input) {
    foreach (explode("\n", $input) as $line) {
        $fields = explode(';', $line);
        $id = array_shift($fields);

        yield $id => $fields;
    }
}

//生成null值,yield可以在没有参数传入的情况下被调用来生成一个null值并配对一个自动的键名
function gen_three_nulls() {
    foreach (range(1, 3) as $i) {
        yield;
    }
}

通过使用yield from关键字从另一个生成器、Traversable对象或数组生成值。然后,外部生成器将从内部生成器,对象或数组中产生所有值,直到该值不再有效为止,然后在外部生成器中继续执行

yield from不会重置key。它保留了Traversable对象或 array返回的键。因此,某些值可能与另一个yield或yield from共享一个公用键,将其插入数组后将用该键覆盖以前的值。

function inner() {
     yield 1; // key 0
     yield 2; // key 1
     yield 3; // key 2
}
function gen() {
     yield 0; // key 0
     yield from inner(); // keys 0-2
     yield 4; // key 1
}

生成器与Iterator对象的比较

示例的方法和类结果时相同的

<?php
function getLinesFromFile($fileName) {
    if (!$fileHandle = fopen($fileName, 'r')) {
        return;
    }
 
    while (false !== $line = fgets($fileHandle)) {
        yield $line;
    }
 
    fclose($fileHandle);
}

// 比较下...

class LineIterator implements Iterator {
    protected $fileHandle;
 
    protected $line;
    protected $i;
 
    public function __construct($fileName) {
        if (!$this->fileHandle = fopen($fileName, 'r')) {
            throw new RuntimeException('Couldn\'t open file "' . $fileName . '"');
        }
    }
 
    public function rewind() {
        fseek($this->fileHandle, 0);
        $this->line = fgets($this->fileHandle);
        $this->i = 0;
    }
 
    public function valid() {
        return false !== $this->line;
    }
 
    public function current() {
        return $this->line;
    }
 
    public function key() {
        return $this->i;
    }
 
    public function next() {
        if (false !== $this->line) {
            $this->line = fgets($this->fileHandle);
            $this->i++;
        }
    }
 
    public function __destruct() {
        fclose($this->fileHandle);
    }
}
?>

 

{/if}