PHP 產生器Generator理解

來源:互聯網
上載者:User
這篇文章介紹的內容是關於PHP 產生器Generator理解,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

轉載整理自:寄凡、風雪之隅、PHP手冊

產生器(Generator)

  • 可解決的問題


引用自官網:產生器提供了一種更容易的方法來實現簡單的對象迭代,相比較定義類實現Iterator介面的方式,效能開銷和複雜性大大降低。產生器允許你在foreach代碼塊中寫代碼來迭代一組資料而不需要在記憶體中建立一個數組,那會使你的記憶體達到上限(劃重點),或者會佔據可觀的處理時間。相反,你可以寫一個產生器函數,就像一個普通的自訂函數一樣,和普通函數只返回一次不同的是, 產生器可以根據需要 yield 多次,以便產生需要迭代的值。


  • Generate實現了Iterator的介面

<?php//產生器Generator implements Iterator {    //返回當前產生的值    public mixed current ( void )    //返回當前產生的鍵    public mixed key ( void )    //產生器繼續執行    public void next ( void )    //重設迭代器,如果迭代已經開始了,這裡會拋出一個異常。    public void rewind ( void )    //向產生器中傳入一個值,當前yield接收值,然後繼續執行下一個yield    public mixed send ( mixed $value )    //向產生器中拋入一個異常    public void throw ( Exception $exception )    //檢查迭代器是否被關閉,已被關閉返回 FALSE,否則返回 TRUE    public bool valid ( void )    //序列化回調    public void __wakeup ( void )    //返回generator函數的傳回值,PHP version 7+    public mixed getReturn ( void )}?>
  • 關鍵字yield

產生器函數的核心是yield關鍵字。它最簡單的調用形式看起來像一個return申明,不同之處在於普通return會傳回值並終止函數的執行,而yield會返回一個值給迴圈調用此產生器的代碼並且只是暫停執行產生器函數. 一個產生器不可以傳回值:這樣做會產生一個編譯錯誤。然而return空是一個有效文法並且它將會終止產生器繼續執行。


yield只能在函數中使用,否則會報PHP Fatal error:The "yield" expression can only be used inside a function,凡是使用了yield關鍵字的函數都會返回一個Generator對象。每次代碼執行到yield語句都會中止執行,返回yield語句中運算式的值給Generator對象,繼續迭代Generator對象時,yield後面的代碼會接著執行,直到所有yield語句全部執行完畢或者有return語句,這個renturn語句只能返回null,即return;,否則會編譯錯誤。

  • 從執行個體出發理解執行過程和可使用函數

1 執行個體一

<?phpfunction xrang($start, $end, $step=1){    for($i=$start; $i<=$end; $i += $step) {        yield $i;  //yield關鍵字定義了中斷點    }   }//foreach (xrang(1, 10000) as $num) {//  echo $num."\n"; //}$rang = xrang(1,2);var_dump($rang).PHP_EOL; //輸出: object(Generator)#1 (0) {}var_dump($rang instanceof Iterator).PHP_EOL; //輸出: bool(true)$key = $rang->key(); var_dump("key: ".$key).PHP_EOL; //輸出: string(6) "key: 0"$valid = $rang->valid();var_dump("valid: ".$valid).PHP_EOL; //輸出: string(8) "valid: 1"$current = $rang->current();var_dump("current: ".$current).PHP_EOL; //輸出: string(10) "current: 1"$rang->next();$key = $rang->key(); var_dump("key: ".$key).PHP_EOL; //輸出: string(6) "key: 1"$valid = $rang->valid();var_dump("valid: ".$valid).PHP_EOL; //輸出: string(8) "valid: 1"$current = $rang->current();var_dump("current: ".$current).PHP_EOL; //輸出: string(10) "current: 2"$rang->next();$key = $rang->key();var_dump("key: ".$key).PHP_EOL; //輸出: string(5) "key: "$valid = $rang->valid();var_dump("valid: ".$valid).PHP_EOL; //輸出: string(7) "valid: "//$rang->rewind(); //重設,目前看到的所有文檔中,rewind()僅在第一次調用Generator的時候隱式執行。產生器開始迭代後調用會拋出Fatal error。?>

2 執行個體二

<?phpfunction gen(){    echo "1111\n";    $ret = (yield 'yield1');    var_dump($ret);    echo "2222\n";    $ret = (yield 'yield2');    var_dump($ret);    //return;}$gen = gen();var_dump($gen->current()).PHP_EOL;$a = $gen->send('ret1');echo "66666\n";var_dump($a).PHP_EOL;echo "77777\n";var_dump($gen->valid()).PHP_EOL;$b = $gen->send('ret2');var_dump($b).PHP_EOL;var_dump($gen->valid()).PHP_EOL;//1111//string(6) "yield1"//string(4) "ret1"//2222//66666//string(6) "yield2"//77777//bool(true)//string(4) "ret2"//NULL//bool(false)?>

2.1 執行過程為:

1.首先調用gen(),進入函數輸出1111,執行到第一個yield關鍵字所在的位置中斷(此時yield運算式的值為定義的"yield1",使用current()擷取當前運算式的值即得到string(6) "yield1")
2.調用send()方法向產生器中傳入值"ret1"(傳入產生器的值.這個值將會被作為產生器當前所在的 yield 的傳回值),此時產生器從當前所在的yield運算式開始迭代,程式繼續往下執行
3.遇到var_dump輸出當前運算式的值"ret1",繼續執行輸出2222
4.繼續執行,程式來到第二個yield中斷點,此時運算式的值為定義值"yield2",因為調用的是send()方法,該方法返回當前所在的yield的值(current()方法值)。(查看send方法的官方文檔)
5.$a擷取到send方法的傳回值即"yield2",繼續執行輸出"66666", $a, "77777"
6.輸出當前產生器是否可用
7.繼續執行,向產生器中傳入值"ret2",產生器開始繼續迭代。此時產生器位於第二個yield運算式,該運算式接受"ret2"作為傳回值賦予變數$ret,列印得到string(4) "ret2"。
8.列印之後,$b == NULL,為NULL的原因因為未徹底理解清楚(疑問之處在於此時的send()方法到底有沒有返回NULL),猜測可能有如下兩個原因:
8.1 一者可能是因為產生器之後沒有中斷點,也沒有傳回值(傳回值不被允許,或者說僅允許返回return; return;用於終止產生器的執行),$gen->send()方法根本就沒有返回任何東西,導致$b == NULL
8.2 二者可能是$gen->send('ret2')傳入值後,產生器迭代完本次的yield,隱式調用了next()和current(),又因為next()下面沒有yield中斷點使得current()返回NULL,導致send()傳回值為NULL
8.3 根據上下文,二的可能性更大

2.2 關於send()方法
send()向產生器中傳入一個值,並且當做 yield 運算式的結果,然後繼續執行產生器。如果當這個方法被調用時,產生器不在 yield 運算式,那麼在傳入值之前,它會先運行到第一個 yield 運算式。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.