<?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的交互.