Generator objects
When a generator function is called for the first time, an object of the internal Generator class is returned. This object implements the Iterator interface in much the same way as a forward-only iterator object would, and provides methods that can be called to manipulate the state of the generator, including sending values to and returning values from it.
生成器语法
一个生成器函数看起来像一个普通的函数,不同的是普通函数返回一个值,而一个生成器可以 yield 生成许多它所需要的值。
当一个生成器被调用的时候,它返回一个可以被遍历的对象.当你遍历这个对象的时候(例如通过一个foreach循环),PHP 将会在每次需要值的时候调用生成器函数,并在产生一个值之后保存生成器的状态,这样它就可以在需要产生下一个值的时候恢复调用状态。
一旦不再需要产生更多的值,生成器函数可以简单退出,而调用生成器的代码还可以继续执行,就像一个数组已经被遍历完了。Note:
一个生成器不可以返回值: 这样做会产生一个编译错误。然而return空是一个有效的语法并且它将会终止生成器继续执行。
yield关键字
生成器函数的核心是yield关键字。它最简单的调用形式看起来像一个return申明,不同之处在于普通return会返回值并终止函数的执行,而yield会返回一个值给循环调用此生成器的代码并且只是暂停执行生成器函数。
Example #1 一个简单的生成值的例子
phpfunctiongen_one_to_three() {for ($i = 1; $i <= 3; $i++) {//注意变量$i的值在不同的yield之间是保持传递的。 yield $i; }}$generator =gen_one_to_three();foreach ($generator as $value) {echo "$value\n";}?>
以上例程会输出:
123Note:
在内部会为生成的值配对连续的整型索引,就像一个非关联的数组。
如果在一个表达式上下文(例如在一个赋值表达式的右侧)中使用yield,你必须使用圆括号把yield申明包围起来。 例如这样是有效的:
$data = (yield $value);
而这样就不合法,并且在PHP5中会产生一个编译错误:
$data = yield $value;
The parenthetical restrictions do not apply in PHP 7.
这个语法可以和生成器对象的Generator::send()方法配合使用。
指定键名来生成值
PHP的数组支持关联键值对数组,生成器也一样支持。所以除了生成简单的值,你也可以在生成值的时候指定键名。
如下所示,生成一个键值对与定义一个关联数组十分相似。
Example #2 生成一个键值对
php/** 下面每一行是用分号分割的字段组合,第一个字段将被用作键名。*/$input = < $fields; }}foreach (input_parser($input) as $id => $fields) {echo "$id:\n";echo " $fields[0]\n";echo " $fields[1]\n";}?>
以上例程会输出:
1: PHP Likes dollar signs2: Python Likes whitespace3: Ruby Likes blocks
和之前生成简单值类型一样,在一个表达式上下文中生成键值对也需要使用圆括号进行包围:
$data = (yield $key => $value);
生成null值
Yield可以在没有参数传入的情况下被调用来生成一个 NULL值并配对一个自动的键名。
Example #3 生成NULLs
phpfunctiongen_three_nulls() {foreach (range(1, 3) as $i) { yield; }}var_dump(iterator_to_array(gen_three_nulls()));?>
以上例程会输出:
array(3) { [0]=>NULL [1]=>NULL [2]=>NULL}
使用引用来生成值
生成函数可以像使用值一样来使用引用生成。这个和returning references from functions(从函数返回一个引用)一样:通过在函数名前面加一个引用符号。
Example #4 使用引用来生成值
phpfunction &gen_reference() {$value = 3;while ($value > 0) { yield$value; }}/** 我们可以在循环中修改$number的值,而生成器是使用的引用值来生成,所以gen_reference()内部的$value值也会跟着变化。*/foreach (gen_reference() as &$number) {echo (--$number).'... ';}?>
以上例程会输出:
2... 1... 0...
Generator delegation via yield from ¶
In PHP 7, generator delegation allows you to yield values from another generator, Traversable object, or array by using the yield from keyword. The outer generator will then yield all values from the inner generator, object, or array until that is no longer valid, after which execution will continue in the outer generator.
If a generator is used with yield from, the yield from expression will also return any value returned by the inner generator.
Example #5 Basic use of yield from
phpfunctioncount_to_ten() { yield1; yield2; yield from [3, 4]; yield fromnew ArrayIterator([5, 6]); yield from seven_eight(); yield9; yield10;}functionseven_eight() { yield7; yield from eight();}functioneight() { yield8;}foreach (count_to_ten() as $num) {echo "$num ";}?>
以上例程会输出:
1 2 3 4 5 6 7 8 9 10
Example #6 yield from and return values
phpfunctioncount_to_ten() { yield1; yield2; yield from [3, 4]; yield fromnew ArrayIterator([5, 6]); yield from seven_eight();returnyield from nine_ten();}functionseven_eight() { yield7; yield from eight();}functioneight() { yield8;}functionnine_ten() { yield9;return 10;}$gen =count_to_ten();foreach ($gen as $num) {echo "$num ";}echo $gen->getReturn();?>
以上例程会输出:
1 2 3 4 5 6 7 8 9 10
Comparing generators with Iterator objects
The primary advantage of generators is their simplicity. Much less boilerplate code has to be written compared to implementing an Iterator class, and the code is generally much more readable. For example, the following function and class are equivalent:
phpfunction getLinesFromFile($fileName) {if (!$fileHandle = fopen($fileName, 'r')) {return; }while (false !== $line = fgets($fileHandle)) { yield$line; }fclose($fileHandle);}//versus...class LineIterator implementsIterator {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 functionvalid() {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); }}?>
This flexibility does come at a cost, however: generators are forward-only iterators, and cannot be rewound once iteration has started. This also means that the same generator can't be iterated over multiple times: the generator will need to either be rebuilt by calling the generator function again, or cloned via the clone keyword.
摘自:http://php.net/manual/zh/language.generators.php
相关文章
相关视频
网友评论
文明上网理性发言,请遵守 新闻评论服务协议我要评论
立即提交
专题推荐独孤九贱-php全栈开发教程
全栈 100W+
主讲:Peter-Zhu 轻松幽默、简短易学,非常适合PHP学习入门
玉女心经-web前端开发教程
入门 50W+
主讲:灭绝师太 由浅入深、明快简洁,非常适合前端学习入门
天龙八部-实战开发教程
实战 80W+
主讲:西门大官人 思路清晰、严谨规范,适合有一定web编程基础学习
php中文网:公益在线php培训,帮助PHP学习者快速成长!
Copyright 2014-2020 https://www.php.cn/ All Rights Reserved | 苏ICP备2020058653号-1