從PHP5.5開始,可以使用生成器來(lái)處理一個(gè)序列枪蘑。生成器是一個(gè)函數(shù)损谦,它不會(huì)調(diào)用return來(lái)返回一個(gè)值,而會(huì)調(diào)用yield(可能在一個(gè)循環(huán)中調(diào)用)岳颇。有了這樣一個(gè)生成器照捡,可以在原先使用數(shù)組的地方調(diào)用這個(gè)生成器函數(shù),然后處理傳遞到y(tǒng)ield關(guān)鍵字的值序列话侧。
生成器函數(shù)的核心是yield關(guān)鍵字栗精。它最簡(jiǎn)單的調(diào)用形式看起來(lái)像一個(gè)return申明,不同之處在于普通return會(huì)返回值并終止函數(shù)的執(zhí)行瞻鹏,而yield會(huì)返回一個(gè)值給循環(huán)調(diào)用此生成器的代碼并且只是暫停執(zhí)行生成器函數(shù)悲立。
例一:使用生成器來(lái)生成一個(gè)平方數(shù)列表
function squares($start, $stop) {
if ($start < $stop) {
for($i = $start; $i <= $stop; $i++){
yield $i => $i * $i;
}
} else {
for($i = $stop; $i <= $start; $i++){
yield $i => $i * $i;
}
}
}
var_dump(squares(1,5));
foreach(squares(1,5) as $k => $v){
printf("%d squared is %d\n",$k,$v);
}
可以在foreach中使用傳入yield的健和值,就像常規(guī)的數(shù)組元素一樣新博。
運(yùn)行結(jié)果如下:
object(Generator)#1 (0) {
}
1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
5 squared is 25
例二:生成器來(lái)重新實(shí)現(xiàn) range() 函數(shù)
標(biāo)準(zhǔn)的 range() 函數(shù)需要在內(nèi)存中生成一個(gè)數(shù)組包含每一個(gè)在它范圍內(nèi)的值薪夕,然后返回該數(shù)組, 結(jié)果就是會(huì)產(chǎn)生多個(gè)很大的數(shù)組。 比如叭披,調(diào)用 range(0, 1000000) 將導(dǎo)致內(nèi)存占用超過 100 MB。
做為一種替代方法, 我們可以實(shí)現(xiàn)一個(gè) xrange() 生成器, 只需要足夠的內(nèi)存來(lái)創(chuàng)建 Iterator 對(duì)象并在內(nèi)部跟蹤生成器的當(dāng)前狀態(tài)玩讳,這樣只需要不到1K字節(jié)的內(nèi)存涩蜘。
function xrange($start, $limit, $step = 1) {
if ($start < $limit) {
if ($step <= 0) {
throw new LogicException('Step must be +ve');
}
for ($i = $start; $i <= $limit; $i += $step) {
yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('Step must be -ve');
}
for ($i = $start; $i >= $limit; $i += $step) {
yield $i;
}
}
}
所以,下面range()和xrange()輸出的結(jié)果是一樣的熏纯。
echo 'Single digit odd numbers from range(): ';
foreach (range(1, 9, 2) as $number) {
echo "$number ";
}
echo "\n";
echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
echo "$number ";
}
注意:
yield 的應(yīng)用場(chǎng)景同诫,一般多用于循環(huán)體,比如數(shù)據(jù)庫(kù)的 fetch 操作樟澜,這樣可以減少內(nèi)存的消耗误窖,ZanPHP 框架就大量的這樣使用叮盘。
但切莫濫用 yield 操作,當(dāng)數(shù)據(jù)量大的時(shí)候霹俺,yield可能會(huì)是一個(gè)高耗時(shí)的操作柔吼,會(huì)使程序性能大大降低。
參考:
官方文檔:
相關(guān)書籍:
- 《PHP經(jīng)典實(shí)例》 David Sklar & Adam Trachtenberg
擴(kuò)展閱讀
在PHP中使用協(xié)程實(shí)現(xiàn)多任務(wù)調(diào)度:
- 譯文 http://www.laruence.com/2015/05/28/3038.html
- 原文 http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html
聽雨閣中聽雨歌 - PHP的生成器丙唧、yield和協(xié)程
貓貓大俠 - PHP yield 分析愈魏,以及協(xié)程的實(shí)現(xiàn),超詳細(xì)版(上)
取個(gè)好名字真難的博客 - php利用yield寫一個(gè)簡(jiǎn)單中間件