寄凡、風雪之隅、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...