摘要:說到中的生成器,有人可能會想到協(xié)程,這里我們先不說如何實現(xiàn)協(xié)程,我們探究下的執(zhí)行過程。如果函數(shù)包含了關(guān)鍵字的,那么函數(shù)執(zhí)行后的返回值永遠都是一個對象。如果函數(shù)內(nèi)部同事包含和該函數(shù)的返回值依然是對象,但是在生成對象時,語句后的代碼被忽略。
說到php中的Generator(生成器),有人可能會想到協(xié)程,這里我們先不說php如何實現(xiàn)協(xié)程,我們探究下Generator的執(zhí)行過程。
Generator是通過yield實現(xiàn),yield 關(guān)鍵字是php5.5版本推出的一個特性。
首先,看下面的代碼:
function gen(){ while(true){ yield "gen "; } } $gen = gen(); echo "Generator";
如果沒有了解過yield的話,你會認為上面代碼執(zhí)行的結(jié)果是:死循環(huán)。但實際上,它會echo出Generator。
到這里,也許你會覺得奇怪,yield怎么可以結(jié)束循環(huán)?下面就為大家說明一下:
Generator提供的方法:
Generator::current — 返回當前產(chǎn)生的值 Generator::key — 返回當前產(chǎn)生的鍵 Generator::next — 生成器繼續(xù)執(zhí)行 Generator::rewind — 重置迭代器 Generator::send — 向生成器中傳入一個值 Generator::throw — 向生成器中拋入一個異常 Generator::valid — 檢查迭代器是否被關(guān)閉 Generator::__wakeup — 序列化回調(diào) 生成器提供了一種更容易的方法來實現(xiàn)簡單的對象迭代(迭代器),相比較定義類實現(xiàn) Iterator 接口的方式,性能開銷和復雜性大大降低。
列子:
function gen(){ for($i=0;$i<5;$i++) { echo (yield $i).$i."
"; } } $gen = gen(); foreach($gen as $k=>$v){ echo "{$k}---{$v}"."
"; }
結(jié)果是:
從上面的結(jié)果,我們可以分析出以下幾點:
1當Generator對象被foreach的時候,內(nèi)部的valid,current,key方法會依次被調(diào)用,其返回值是foreach語句的value和key。
2循環(huán)的終止條件則根據(jù)valid方法的返回而定。如果返回的是true則繼續(xù)循環(huán),如果是false則終止整個循環(huán),結(jié)束遍歷。
3一次循環(huán)體結(jié)束之后,將調(diào)用next進行下一次的循環(huán)直到valid返回false。而rewind方法則是在整個循環(huán)開始前被調(diào)用(也就是生成Generator對象時),這樣保證了我們多次遍歷得到的結(jié)果都是一致的。
下面我們來證明一下這個流程:
$gen = gen();
echo $gen->key();//結(jié)果是0,生成Generator對象時,rewind已經(jīng)執(zhí)行。
echo $gen->key()."----".$gen->current();// 0----0
var_dump($gen->next());//var_dump值是null,但是還會echo出多一個0;這個0是怎樣來的呢?原因是:next()執(zhí)行后,第1個yield到第二個yieldz之間的的語法被執(zhí)行,即是:echo (yield $i).$i."
";由于next()是沒有返回值,即(yield $i)這個表達式?jīng)]有值,而$i的值是0;
echo $gen->key()."----".$gen->current();// 1----1 目前是第2個yield
上面這個例子可以證明,Generator內(nèi)部的流程,特別注意next()的理解。
最后,我們說一下,send():
官方解析:向生成器中傳入一個值,并且當做 yield 表達式的結(jié)果,然后繼續(xù)執(zhí)行生成器。如果當這個方法被調(diào)用時,生成器不在 yield 表達式,那么在傳入值之前,它會先運行到第一個 yield 表達式。
翻譯下的結(jié)論是:
send()方法主要用于發(fā)送數(shù)據(jù)給當前yield,即yield表達式被當作一個值被替換,且繼續(xù)執(zhí)行下一個yield,即next()
證明例子:
$gen = gen();
$gen->send(666);//6660
6660結(jié)果分析:首先把666代替當前yield表達式的值,然后執(zhí)行next(),即運行echo (yield $i).$i."
",當前yield是666,所以最終結(jié)果是:6660。注意與next()的區(qū)別?。?!
總結(jié):
1.yield只能用于函數(shù)內(nèi)部,在非函數(shù)內(nèi)部運用會拋出錯誤。
2.如果函數(shù)包含了yield關(guān)鍵字的,那么函數(shù)執(zhí)行后的返回值永遠都是一個Generator對象。
3.如果函數(shù)內(nèi)部同事包含yield和return 該函數(shù)的返回值依然是Generator對象,但是在生成Generator對象時,return語句后的代碼被忽略。
4.Generator類實現(xiàn)了Iterator接口。
5.可以通過返回的Generator對象內(nèi)部的方法,獲取到函數(shù)內(nèi)部yield后面表達式的值。
6.可以通過Generator的send方法給yield 關(guān)鍵字賦一個值。
7.一旦返回的Generator對象被遍歷完成,便不能調(diào)用他的rewind方法來重置。
8.Generator對象不能被clone關(guān)鍵字克隆 。
實際應用:
1.協(xié)程
2.Genenrator返回的是迭代器,在處理大數(shù)據(jù)的時候不用一次性的加載到內(nèi)存中,可看http://php.net/manual/zh/lang...。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/28265.html
摘要:的方法在中,提供了方法來拋出異常??偨Y(jié)關(guān)于生成器的異常處理,這里來進行一下總結(jié)。最近在研究使用實現(xiàn)半?yún)f(xié)程,而這個過程中,對異常的處理,是非常重要的。但是的運行方式?jīng)Q定了異常處理比較難以理解。 本文是我在研究 PHP 異步編程時的總結(jié)。對于相當多的 PHPer 來說,可能都不知道 Generator,或者對 Generaotr 的流程不是很熟悉。因為 Generator 使得程序不再是順...
摘要:本文先回顧生成器,然后過渡到協(xié)程編程。其作用主要體現(xiàn)在三個方面數(shù)據(jù)生成生產(chǎn)者,通過返回數(shù)據(jù)數(shù)據(jù)消費消費者,消費傳來的數(shù)據(jù)實現(xiàn)協(xié)程。解決回調(diào)地獄的方式主要有兩種和協(xié)程。重點應當關(guān)注控制權(quán)轉(zhuǎn)讓的時機,以及協(xié)程的運作方式。 轉(zhuǎn)載請注明文章出處: https://tlanyan.me/php-review... PHP回顧系列目錄 PHP基礎 web請求 cookie web響應 sess...
摘要:在中,我們都知道,有一個函數(shù)叫做,用來生成一個等差數(shù)列的數(shù)組,然后我們可以用這個數(shù)組進行的迭代。這一段代碼就會輸出首項為,末項為,公差為的等差數(shù)列。它的執(zhí)行順序是這樣的。 何為 Generator 從 PHP 5.5 開始,PHP 加入了一個新的特性,那就是 Generator,中文譯為生成器。生成器可以簡單地用來實現(xiàn)對象的迭代,讓我們先從官方的一個小例子說起。 xrange 在 PH...
閱讀 3167·2021-11-22 09:34
閱讀 2806·2021-09-22 15:28
閱讀 835·2021-09-10 10:51
閱讀 1865·2019-08-30 14:22
閱讀 2332·2019-08-30 14:17
閱讀 2746·2019-08-30 11:01
閱讀 2306·2019-08-29 17:19
閱讀 3674·2019-08-29 13:17