您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)如何在PHP中使用生成器,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
一、phpStudy,是一個(gè)新手入門最常用的開發(fā)環(huán)境。二、WampServer,WampServer也同樣的也是和phpStudy一樣操作簡(jiǎn)單對(duì)小白比較友好。三、XAMPP,XAMPP(Apache+MySQL+PHP+PERL)是一個(gè)功能強(qiáng)大的建站集成軟件包;四、MAMP,MAMP分為兩種MAMP和MAMP Pro for Mac。五、寶塔面板,寶塔面板是一款服務(wù)器管理軟件,支持windows和linux系統(tǒng)。六、UPUPW,UPUPW是目前Windows平臺(tái)下最具特色的Web服務(wù)器PHP套件。
生成器是一個(gè)用于迭代的迭代器。它提供了一種更容易的方式來實(shí)現(xiàn)簡(jiǎn)單的對(duì)象迭代,相比較定義類實(shí)現(xiàn)Iterator接口的方式,性能開銷和復(fù)雜性大大降低。
說了半天不如直接看看代碼更直觀。
function test1() { for ($i = 0; $i < 3; $i++) { yield $i + 1; } yield 1000; yield 1001; } foreach (test1() as $t) { echo $t, PHP_EOL; } // 1 // 2 // 3 // 1000 // 1001
就是這么簡(jiǎn)單的一段代碼。首先,生成器必須在方法中并使用 yield 關(guān)鍵字;其次,每一個(gè) yield 可以看作是一次 return ;最后,外部循環(huán)時(shí),一次循環(huán)取一個(gè) yield 的返回值。在這個(gè)例子,循環(huán)三次返回了1、2、3這三個(gè)數(shù)字。然后在循環(huán)外部又寫了兩行 yield 分別輸出了1000和1001。因此,外部的 foreach 一共循環(huán)輸出了五次。
很神奇吧,明明是一個(gè)方法,為什么能夠循環(huán)它而且還是很奇怪的一種返回循環(huán)體的格式。我們直接打印這個(gè) test() 方法看看打印的是什么:
// 是一個(gè)生成器對(duì)象 var_dump(test1()); // Generator Object // ( // )
當(dāng)使用了 yield 進(jìn)行內(nèi)容返回后,返回的是一個(gè) Generator 對(duì)象。這個(gè)對(duì)象就叫作生成器對(duì)象,它不能直接被 new 實(shí)例化,只能通過生成器函數(shù)這種方式返回。這個(gè)類包含 current() 、 key() 等方法,而且最主要的這個(gè)類實(shí)現(xiàn)了 Iterator 接口,所以,它就是一個(gè)特殊的迭代器類。
Generator implements Iterator { /* 方法 */ public current ( void ) : mixed public key ( void ) : mixed public next ( void ) : void public rewind ( void ) : void public send ( mixed $value ) : mixed public throw ( Exception $exception ) : void public valid ( void ) : bool public __wakeup ( void ) : void }
搞了半天不就是個(gè)迭代器嘛?搞這么麻煩干嘛,直接用迭代器或者在方法中直接返回一個(gè)數(shù)組不就好了嗎?沒錯(cuò),正常情況下真的沒有這么麻煩,但是如果是在數(shù)據(jù)量特別大的情況下,這個(gè)生成器就能發(fā)揮它的強(qiáng)大威力了。生成器最最強(qiáng)大的部分就在于,它不需要一個(gè)數(shù)組或者任何的數(shù)據(jù)結(jié)構(gòu)來保存這一系列數(shù)據(jù)。每次迭代都是代碼執(zhí)行到 yield 時(shí)動(dòng)態(tài)返回的。因此,生成器能夠極大的節(jié)約內(nèi)存。
// 內(nèi)存占用測(cè)試 $start_time = microtime(true); function test2($clear = false) { $arr = []; if($clear){ $arr = null; return; } for ($i = 0; $i < 1000000; $i++) { $arr[] = $i + 1; } return $arr; } $array = test2(); foreach ($array as $val) { } $end_time = microtime(true); echo "time: ", bcsub($end_time, $start_time, 4), PHP_EOL; echo "memory (byte): ", memory_get_usage(true), PHP_EOL; // time: 0.0513 // memory (byte): 35655680 $start_time = microtime(true); function test3() { for ($i = 0; $i < 1000000; $i++) { yield $i + 1; } } $array = test3(); foreach ($array as $val) { } $end_time = microtime(true); echo "time: ", bcsub($end_time, $start_time, 4), PHP_EOL; echo "memory (byte): ", memory_get_usage(true), PHP_EOL; // time: 0.0517 // memory (byte): 2097152
上述代碼只是簡(jiǎn)單的進(jìn)行 1000000 個(gè)循環(huán)后獲取結(jié)果,不過也可以直觀地看出。使用生成器的版本僅僅消耗了 2M 的內(nèi)存,而未使用生成器的版本則消耗了 35M 的內(nèi)存,直接已經(jīng)10多倍的差距了,而且越大的量差距超明顯。因此,有大神將生成器說成是PHP中最被低估了的一個(gè)特性。
接下來我們來看看生成器的一些基本的應(yīng)用方式。
生成器當(dāng)然也可以返回空值,直接 yield; 不帶任何值就可以返回一個(gè)空值了。而在方法中直接使用 return; 也可以用來中斷生成器的繼續(xù)執(zhí)行。下面的代碼我們?cè)?\i = 4; 的時(shí)候返回的是個(gè)空值,也就是不會(huì)輸出 5 (因?yàn)槲覀兎祷氐氖莍=4;的時(shí)候返回的是個(gè)空值,也就是不會(huì)輸出5(因?yàn)槲覀兎祷氐氖莍 + 1 )。然后在 $i == 7 的時(shí)候使用 return; 中斷生成器的繼續(xù)執(zhí)行,也就是循環(huán)最多只會(huì)輸出到 7 就結(jié)束了。
// 返回空值以及中斷 function test4() { for ($i = 0; $i < 10; $i++) { if ($i == 4) { yield; // 返回null值 } if ($i == 7) { return; // 中斷生成器執(zhí)行 } yield $i + 1; } } foreach (test4() as $t) { echo $t, PHP_EOL; } // 1 // 2 // 3 // 4 // 5 // 6 // 7
不要驚訝,生成器真的是可以返回鍵值對(duì)形式的可遍歷對(duì)象供 foreach 使用的,而且語法非常好記: yield key => value; 是不是和數(shù)組項(xiàng)的定義形式一模一樣,非常直觀好理解。
function test5() { for ($i = 0; $i < 10; $i++) { yield 'key.' . $i => $i + 1; } } foreach (test5() as $k=>$t) { echo $k . ':' . $t, PHP_EOL; } // key.0:1 // key.1:2 // key.2:3 // key.3:4 // key.4:5 // key.5:6 // key.6:7 // key.7:8 // key.8:9 // key.9:10
我們可以通過 Generator::send 方法來向生成器中傳入一個(gè)值。傳入的這個(gè)值將會(huì)被當(dāng)做生成器當(dāng)前 yield 的返回值。然后我們根據(jù)這個(gè)值可以做一些判斷,比如根據(jù)外部條件中斷生成器的執(zhí)行。
function test6() { for ($i = 0; $i < 10; $i++) { // 正常獲取循環(huán)值,當(dāng)外部send過來值后,yield獲取到的就是外部傳來的值了 $data = (yield $i + 1); if($data == 'stop'){ return; } } } $t6 = test6(); foreach($t6 as $t){ if($t == 3){ $t6->send('stop'); } echo $t, PHP_EOL; } // 1 // 2 // 3
上述代碼理解起來可能比較繞,但是注意記住注釋的那行話就行了(正常獲取循環(huán)值,當(dāng)外部send過來值后,yield獲取到的就是外部傳來的值了)。另外,變量獲取 yield 的值,必須要用括號(hào)括起來。
yield from 語法其實(shí)就是指的從另一個(gè)可迭代對(duì)象中一個(gè)一個(gè)的獲取數(shù)據(jù)并形成生成器返回。直接看代碼
function test7() { yield from [1, 2, 3, 4]; yield from new ArrayIterator([5, 6]); yield from test1(); } foreach (test7() as $t) { echo 'test7:', $t, PHP_EOL; } // test7:1 // test7:2 // test7:3 // test7:4 // test7:5 // test7:6 // test7:1 // test7:2 // test7:3 // test7:1000
在 test7() 方法中,我們使用 yield from 分別從普通數(shù)組、迭代器對(duì)象、另一個(gè)生成器中獲取數(shù)據(jù)并做為當(dāng)前生成器的內(nèi)容進(jìn)行返回。
抱歉,生成器是不能用count來獲取它的數(shù)量的。
$c = count(test1()); // Warning: count(): Parameter must be an array or an object that implements Countable // echo $c, PHP_EOL;
使用 count 來獲取生成器的數(shù)量將直接報(bào) Warning 警告。直接輸出將會(huì)一直顯示是 1 ,因?yàn)?count 的特性(強(qiáng)制轉(zhuǎn)換成數(shù)組都會(huì)顯示 1 )。
// 利用生成器生成斐波那契數(shù)列 function fibonacci($item) { $a = 0; $b = 1; for ($i = 0; $i < $item; $i++) { yield $a; $a = $b - $a; $b = $a + $b; } } $fibo = fibonacci(10); foreach ($fibo as $value) { echo "$value\n"; }
上述就是小編為大家分享的如何在PHP中使用生成器了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。