PHP 生成器Generator理解

2021-08-18 20:53:21 字數 3759 閱讀 2143

寄凡、風雪之隅、php手冊

生成器(generator)

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

<?php

//生成器

generator implements iterator

?>

生成器函式的核心是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 例項一

<?php

function xrang($start, $end, $step=1)

}//foreach (xrang(1, 10000) as $num)

$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 例項二

<?php

function gen()

$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 表示式。

Generator生成器基礎

生成器函式是es6提供的一種非同步程式設計解決方案,語法行為與傳統函式完全不同 function gen let iterator gen console.log iterator 不會輸出hello 是乙個迭代器物件 需要呼叫next方法才會輸出 iterator.next 輸出結果 yield相...

php的Generator生成器及yield

官方文件 生成器提供了一種更容易的方法來實現簡單的物件迭代,相比較定義類實現iterator介面的方式,效能開銷和複雜性大大降低。生成器允許你在foreach 塊中寫 來迭代一組資料而不需要在記憶體中建立乙個陣列,那會使你的記憶體達到上限,或者會佔據可觀的處理時間。相反,你可以寫乙個生成器函式,就像...

Python程式設計 generator生成器

列表生成式 lst for i in range 10 print lst 0,2,4,6,8,10,12,14,16,18 相當於 lst i 2 for i in range 10 print lst 0,2,4,6,8,10,12,14,16,18 lst i 2 for i in range...