php中Generator的執行過程

說到php中的Generator(生成器),有人可能會想到協程,這裏咱們先不說php如何實現協程,咱們探究下Generator的執行過程。
Generator是經過yield實現,yield 關鍵字是php5.5版本推出的一個特性。
首先,看下面的代碼:php

function gen(){
                  while(true){
                    yield "gen\n";
                  }
                }
                
                $gen = gen();
                echo "Generator";

若是沒有了解過yield的話,你會認爲上面代碼執行的結果是:死循環。但實際上,它會echo出Generator。函數

到這裏,也許你會以爲奇怪,yield怎麼能夠結束循環?下面就爲你們說明一下:性能

Generator提供的方法:大數據

Generator::current — 返回當前產生的值
Generator::key — 返回當前產生的鍵
Generator::next — 生成器繼續執行
Generator::rewind — 重置迭代器
Generator::send — 向生成器中傳入一個值
Generator::throw — 向生成器中拋入一個異常
Generator::valid — 檢查迭代器是否被關閉
Generator::__wakeup — 序列化回調

生成器提供了一種更容易的方法來實現簡單的對象迭代(迭代器),相比較定義類實現 Iterator 接口的方式,性能開銷和複雜性大大下降。

列子:spa

function gen(){
                   for($i=0;$i<5;$i++)
                   {
                       echo (yield $i).$i.'<br/>';
                   }
            }
             $gen = gen();
             foreach($gen as $k=>$v){
                 echo "{$k}---{$v}".'<br/>';
             }

結果是:.net

clipboard.png

從上面的結果,咱們能夠分析出如下幾點:
1當Generator對象被foreach的時候,內部的valid,current,key方法會依次被調用,其返回值是foreach語句的value和key。
2循環的終止條件則根據valid方法的返回而定。若是返回的是true則繼續循環,若是是false則終止整個循環,結束遍歷。
3一次循環體結束以後,將調用next進行下一次的循環直到valid返回false。而rewind方法則是在整個循環開始前被調用(也就是生成Generator對象時),這樣保證了咱們屢次遍歷獲得的結果都是一致的。翻譯

下面咱們來證實一下這個流程:code

$gen = gen();
echo $gen->key();//結果是0,生成Generator對象時,rewind已經執行。
echo $gen->key().'----'.$gen->current();// 0----0
var_dump($gen->next());//var_dump值是null,可是還會echo出多一個0;這個0是怎樣來的呢?緣由是:next()執行後,第1個yield到第二個yieldz之間的的語法被執行,便是:echo (yield $i).$i.'<br/>';因爲next()是沒有返回值,即(yield $i)這個表達式沒有值,而$i的值是0;
echo $gen->key().'----'.$gen->current();// 1----1 目前是第2個yield協程

上面這個例子能夠證實,Generator內部的流程,特別注意next()的理解。對象

最後,咱們說一下,send():

官方解析:向生成器中傳入一個值,而且當作 yield 表達式的結果,而後繼續執行生成器。若是當這個方法被調用時,生成器不在 yield 表達式,那麼在傳入值以前,它會先運行到第一個 yield 表達式。

翻譯下的結論是:
send()方法主要用於發送數據給當前yield,即yield表達式被看成一個值被替換,且繼續執行下一個yield,即next()

證實例子:
$gen = gen();
$gen->send(666);//6660

6660結果分析:首先把666代替當前yield表達式的值,而後執行next(),即運行echo (yield $i).$i.'<br/>',當前yield是666,因此最終結果是:6660。注意與next()的區別!!!

總結:
1.yield只能用於函數內部,在非函數內部運用會拋出錯誤。
2.若是函數包含了yield關鍵字的,那麼函數執行後的返回值永遠都是一個Generator對象。
3.若是函數內部同事包含yield和return 該函數的返回值依然是Generator對象,可是在生成Generator對象時,return語句後的代碼被忽略。
4.Generator類實現了Iterator接口。
5.能夠經過返回的Generator對象內部的方法,獲取到函數內部yield後面表達式的值。
6.能夠經過Generator的send方法給yield 關鍵字賦一個值。
7.一旦返回的Generator對象被遍歷完成,便不能調用他的rewind方法來重置。
8.Generator對象不能被clone關鍵字克隆 。

實際應用:
1.協程
2.Genenrator返回的是迭代器,在處理大數據的時候不用一次性的加載到內存中,可看http://php.net/manual/zh/lang...

相關文章
相關標籤/搜索