成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

PHP學(xué)習(xí)筆記系列:PHP生成器概覽

liuhh / 2015人閱讀

摘要:所以生成器首先是一個(gè)迭代器,也就是說(shuō)它可以使用進(jìn)行遍歷。普通函數(shù)后,函數(shù)會(huì)被從棧中移除,中止執(zhí)行,但是會(huì)保存生成器的狀態(tài),當(dāng)被再次調(diào)用時(shí),迭代器會(huì)從上次的地方恢復(fù)調(diào)用狀態(tài)繼續(xù)執(zhí)行。

生成器概述

PHP從5.5.0版本開(kāi)始支持生成器(Generator),根據(jù)PHP官方文檔的說(shuō)法:生成器提供了一種更容易的方法來(lái)實(shí)現(xiàn)簡(jiǎn)單的對(duì)象迭代,相比較定義類(lèi)實(shí)現(xiàn) Iterator 接口的方式,性能開(kāi)銷(xiāo)和復(fù)雜性大大降低。

所以生成器首先是一個(gè)迭代器(Iterator),也就是說(shuō)它可以使用foreach進(jìn)行遍歷。生成器就類(lèi)似一個(gè)返回?cái)?shù)組的函數(shù),它可以接收參數(shù),并被調(diào)用。

我們以range()函數(shù)為例,把它實(shí)現(xiàn)為生成器:


結(jié)果看起來(lái)是一樣的:

results from range():1 4 7 10 
results from xrange():1 4 7 10

可以看到,xrange()使用yield關(guān)鍵字,而不是return。使用yield關(guān)鍵字后,調(diào)用函數(shù)時(shí)就會(huì)返回一個(gè)生成器(Generator)的對(duì)象(Generator是一個(gè)內(nèi)部類(lèi),不能直接實(shí)例化),這個(gè)對(duì)象實(shí)現(xiàn)了Iterator接口,所以正如前面說(shuō)過(guò),生成器是迭代器,我們可以通過(guò)以下代碼驗(yàn)證下:


跟普通函數(shù)只返回一次值不同的是, 生成器可以根據(jù)需要yield多次,以便生成需要迭代的值。 普通函數(shù)return后,函數(shù)會(huì)被從棧中移除,中止執(zhí)行,但是yield會(huì)保存生成器的狀態(tài),當(dāng)被再次調(diào)用時(shí),迭代器會(huì)從上次yield的地方恢復(fù)調(diào)用狀態(tài)繼續(xù)執(zhí)行。看下下面代碼的執(zhí)行結(jié)果:


The generator has started
return 1
Yielded 1
return 4
Yielded 4
return 7
Yielded 7
return 10
Yielded 10
The generator has ended

可以看到,每次迭代,在yield后,代碼不會(huì)繼續(xù)執(zhí)行,而是先執(zhí)行調(diào)用者的代碼,然后在下一次迭代,迭代器的代碼繼續(xù)執(zhí)行,一直到?jīng)]有yield可以執(zhí)行為止。

生成器語(yǔ)法 return值

前面說(shuō)過(guò),函數(shù)里使用yield關(guān)鍵字后,在被調(diào)用時(shí)會(huì)返回一個(gè)生成器對(duì)象,所以生成器函數(shù)的核心是yield關(guān)鍵字。它的調(diào)用形式看起來(lái)像一個(gè)return申明,不同之處在于普通return會(huì)返回值并終止函數(shù)的執(zhí)行,而yield會(huì)返回一個(gè)值給循環(huán)調(diào)用此生成器的代碼并且只是暫停執(zhí)行生成器函數(shù)。

一個(gè)生成器函數(shù)不可以通過(guò)return返回值(很顯而易見(jiàn),因?yàn)樯善骱瘮?shù)被調(diào)用后返回的是一個(gè)生成器對(duì)象), 在PHP 5.6版本及之前,如果使用return返回一個(gè)值的話,會(huì)產(chǎn)生一個(gè)編譯錯(cuò)誤:

PHP Fatal error:  Generators cannot return values using "return" in /path/to/php_code.php on line x

在PHP 7中,可以使用getReturn()得到return的返回值:

getReturn(); // 1

不過(guò)有個(gè)前提,就是生成器已經(jīng)完成了迭代,否則會(huì)報(bào)以下錯(cuò)誤:

PHP Fatal error:  Uncaught Exception: Cannot get return value of a generator that hasn"t returned in /path/to/php_code.php:x

另外,return空無(wú)論是在PHP 7還是之前支持生成器的PHP版本都是一個(gè)有效的語(yǔ)法,它會(huì)終止生成器繼續(xù)執(zhí)行。

生成null值

如果yield后面沒(méi)有跟任何的參數(shù),則會(huì)返回NULL值:


輸出:

array(3) {
  [0]=>
  NULL
  [1]=>
  NULL
  [2]=>
  NULL
}
生成鍵值對(duì)

PHP的數(shù)組支持關(guān)聯(lián)鍵值對(duì)數(shù)組,生成器其實(shí)也支持生成鍵值對(duì):

 $i;
    }
}

var_dump(iterator_to_array(gen_key_values()));

輸出:

array(3) {
  ["key0"]=>
  int(0)
  ["key1"]=>
  int(1)
  ["key2"]=>
  int(2)
}
注入值

除了生成值,生成器還能從外面接收值。通過(guò)生成器對(duì)象的send()方法,我們可以從外面?zhèn)鬟f值到生成器里。這個(gè)值會(huì)作為yield表達(dá)式的結(jié)果,我們可以利用這個(gè)值來(lái)做一些計(jì)算或者其他事情,例如根據(jù)值來(lái)中止生成器的執(zhí)行:

send("stop");
    }
    echo $v . PHP_EOL;
}

輸出結(jié)果:

0
1
2
3

send()方法的返回值是下一個(gè)yield的值,如果沒(méi)有,則返回NULL。

需要注意的是, 如果在一個(gè)表達(dá)式上下文(例如上面的情況,在一個(gè)賦值表達(dá)式的右側(cè))中使用yield,必須使用圓括號(hào)把yield申明包圍起來(lái)。 例如:

$data = (yield $value);

下面的代碼在PHP5中會(huì)產(chǎn)生一個(gè)編譯錯(cuò)誤:

$data = yield $value;
yield from表達(dá)式

在PHP 7里,使用yield from表達(dá)式允許你在生成器里通過(guò)其他生成器、Traversable對(duì)象或者數(shù)組產(chǎn)生值。這種方式叫做生成器委托。下面的例子來(lái)自官方文檔:


輸出:

1 2 3 4 5 6 7 8 9 10 
為什么不使用Iterator

生成器也是迭代器,那為什么不直接使用迭代器呢?其實(shí)文章剛開(kāi)始就說(shuō)到了:生成器提供了一種更容易的方法來(lái)實(shí)現(xiàn)簡(jiǎn)單的對(duì)象迭代,相比較定義類(lèi)實(shí)現(xiàn) Iterator 接口的方式,性能開(kāi)銷(xiāo)和復(fù)雜性大大降低。

更低的復(fù)雜度

要使用迭代器,必須要實(shí)現(xiàn)Iterator接口里的所有方法,這無(wú)疑大大增加了使用成本,具體可以看看官方文檔里的例子:Comparing generators with Iterator objects。

更低的內(nèi)存占用

除了復(fù)雜度,另外一個(gè)使用生成器的原因就是使用生成器可以大大減少內(nèi)存的使用。以文章最開(kāi)始的例子為例,標(biāo)準(zhǔn)的 range() 函數(shù)需要在內(nèi)存中生成一個(gè)數(shù)組包含每一個(gè)在它范圍內(nèi)的值,然后返回該數(shù)組,這樣就會(huì)產(chǎn)生多個(gè)很大的數(shù)組。 比如,調(diào)用 range(0, 1000000) 將導(dǎo)致內(nèi)存占用超過(guò) 100 MB。而我們實(shí)現(xiàn)的xrange()生成器, 只需要足夠的內(nèi)存來(lái)創(chuàng)建 生成器對(duì)象并在內(nèi)部跟蹤生成器的當(dāng)前狀態(tài),這樣只需要不到1K字節(jié)的內(nèi)存。


測(cè)試結(jié)果:

Test for range():
time:0.2319
memory (byte):144376424
Test for xrange():
time:0.1382
memory (byte):0

可以看到,在內(nèi)存占用上,xrange()遠(yuǎn)遠(yuǎn)低于range(),甚至在速度上也占優(yōu)。在諸如讀取文件之類(lèi)的場(chǎng)景,使用生成器也可以大大減少內(nèi)存的占用:


使用生成器實(shí)現(xiàn)協(xié)程

PHP的生成器特性使得在PHP中實(shí)現(xiàn)協(xié)程成為了可能,下面是一篇使用協(xié)程實(shí)現(xiàn)多任務(wù)調(diào)度的文章,雖然是12年的文章,但是仍然很有參考意義:

http://nikic.github.io/2012/1...

參考

http://php.net/manual/zh/lang...

https://www.sitepoint.com/gen...

http://nikic.github.io/2012/1...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/23312.html

相關(guān)文章

  • AI開(kāi)發(fā)書(shū)籍分享

    摘要:編程書(shū)籍的整理和收集最近一直在學(xué)習(xí)深度學(xué)習(xí)和機(jī)器學(xué)習(xí)的東西,發(fā)現(xiàn)深入地去學(xué)習(xí)就需要不斷的去提高自己算法和高數(shù)的能力然后也找了很多的書(shū)和文章,隨著不斷的學(xué)習(xí),也整理了下自己的學(xué)習(xí)筆記準(zhǔn)備分享出來(lái)給大家后續(xù)的文章和總結(jié)會(huì)繼續(xù)分享,先分享一部分的 編程書(shū)籍的整理和收集 最近一直在學(xué)習(xí)deep learning深度學(xué)習(xí)和機(jī)器學(xué)習(xí)的東西,發(fā)現(xiàn)深入地去學(xué)習(xí)就需要不斷的去提高自己算法和高數(shù)的能力然后...

    huayeluoliuhen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

liuhh

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<