<?php function gen() { $ret = (yield ‘yield1‘); var_dump($ret); $ret = (yield ‘yield2‘); var_dump($ret); } $gen = gen(); var_dump($gen->current()); // string(6) "yield1" var_dump($gen->send(‘ret1‘)); // string(4) "ret1" (the first var_dump in gen) // string(6) "yield2" (the var_dump of the ->send() return value) var_dump($gen->send(‘ret2‘)); // string(4) "ret2" (again from within gen) // NULL (the return value of ->send()) ?>
上面的代码首先是调用函数gen生成一个Generator对象,然后调用这个对象的current方法返回第一个值,显然它是第一个yield语句的返回值,也就是‘yield1‘,这个时候gen函数的执行就会被中止,接着执行var_dump($g->send(‘ret1‘));。
调用$g->send(‘ret1‘),传入参数为字符串‘ret1‘,按照上面的说明,它会赋值给第一个yield表达式,也就是(yield ‘yield1‘)中的yield(注意:这个时候不包括‘yield1‘),它的值为‘ret1‘,然后会赋值给$ret,所以第二个输出‘ret1‘就是gen函数中的第一个var_dump输出的。此时对Generator对象的迭代会恢复继续执行,实际上就是调用了一次next函数,它会执行到下一个yield语句:yield ‘yield2‘,这个语句会返回‘yield2‘,它会作为$g->send(‘ret1‘)的返回值,所以函数外第二个var_dump会输出‘yield2‘。
最后再次调用send函数,这次传入的参数为字符串‘ret2‘,跟上面一样,Generator对象当前位置的元素是在gen函数的第二个yield上,所以’ret2‘会被传递给第二个yield表达式,也就是作为(yield ‘yield2‘)中的yield的值,并且会被赋值给$ret变量,然后gen函数恢复执行,它会执行gen函数中的最后一个var_dump,此时对Generator对象$g的遍历也结束了,第二个send函数的返回值为NULL,这也是函数外的最后一个var_dump的输出。
读了这么一段分析以后,你现在最大的困惑是什么呢?
我最大的困惑是为什么同一个yied关键字,它既是语句,又是表达式,而且这两种情况是同时存在的:
- 对于所有在generator函数中出现的yield,首先它都是语句,而跟在yield后面的任何表达式的值将作为调用generator函数的返回值,如果yield后面没有任何表达式(变量、常量都是表达式),那么它会返回NULL,这一点跟return语句一致。
- yield也是表达式,它的值就是send函数传过来的值(相当于一个特殊变量,只不过赋值是通过send函数进行的)。只要调用send方法,并且Generator对象的迭代并未终结,那么当前位置的yield就会得到send方法传递过来的值,这跟generator函数有没有把这个值赋值给某个变量没有任何关系。
从上面两点我们就可以看出,任何时候yield关键词都即是语句——可以为generator函数返回值,也是表达式——可以接收Generator对象发过来的值。
-------------------------分界线:上面是摘抄的,下面是自己的疑问---------------------------
讲的很好。但有点疑问就是:
在执行完gen中的var_dump之后,generator应该终止啊。但是,为什么却又恢复了,继续执行下一条yield语句呢。 我猜是因为当yield作为表达式的时候,generator并没有进行迭代。只有yield被当做了语句执行之后,generator才会终止吧。
------------再次补充:关于yield既是表达式又是语句的理解--------
<?php function gen() { for($i=1;$i<=100;$i++) { $cmd = (yield $i); if($cmd==‘stop‘) { return; } } } $gen = gen(); $i=0; foreach($gen as $item) { echo $item."\n"; if($i>=10) { $gen->send(‘stop‘); } $i++; } ?>这是个很好地例子:
1、yield作为语句(类似return语句),会返回$i给调用者。
2、yield作为表达式。获取send函数传递值,赋值给$cmd。
3、实现Generator对象和generator函数的通信。这个很重要。应该能实现很多generator的交互.