你有沒(méi)有想過(guò) "在 PHP
中使用 yield 會(huì)有什么益處"琼讽,我將為你節(jié)省一些谷歌搜索的時(shí)間; 我列出了一些要向你介紹的要點(diǎn)來(lái)全面認(rèn)知 yield:
- 什么是 yield。
- yield & return 的區(qū)別。
- yield 有什么選項(xiàng)。
- 結(jié)論焚辅。
- 參考。
1. 什么是 "yield"
生成器函數(shù)看上去就像一個(gè)普通函數(shù)硕并, 除了不是返回一個(gè)值之外法焰, 生成器會(huì)根據(jù)需求產(chǎn)生更多的值。
來(lái)看以下的例子:
function getValues() {
yield 'value';
}
// 輸出字符串 "value"
echo getValues();
當(dāng)然倔毙, 這不是他生效的方式埃仪, 前面的例子會(huì)給你一個(gè)致命的錯(cuò)誤: 類生成器的對(duì)象不能被轉(zhuǎn)換成字符串
, 讓我們清楚的說(shuō)明:
2. "yield" & "return" 的區(qū)別
前面的錯(cuò)誤意味著 getValues()
方法不會(huì)如預(yù)期返回一個(gè)字符串陕赃,讓我們檢查一下他的類型:
function getValues() {
return 'value';
}
var_dump(getValues()); // string(5) "value"
function getValues() {
yield 'value';
}
var_dump(getValues()); // class Generator#1 (0) {}
生成器 類實(shí)現(xiàn)了 生成器 接口卵蛉, 這意味著你必須遍歷 getValue()
方法來(lái)取值:
foreach (getValues() as $value) {
echo $value;
}
// 使用變量也是好的
$values = getValues();
foreach ($values as $value) {
echo $value;
}
但這不是唯一的不同!
一個(gè)生成器運(yùn)行你寫使用循環(huán)來(lái)迭代一維數(shù)組的代碼么库,而不需要在內(nèi)存中創(chuàng)建是一個(gè)數(shù)組傻丝,這可能會(huì)導(dǎo)致你超出內(nèi)存限制。
在下面的例子里我們創(chuàng)建一個(gè)有 800,000 元素的數(shù)字同時(shí)從 getValues()
方法中返回他诉儒,同時(shí)在此期間葡缰,我們將使用函數(shù) memory_get_usage() 來(lái)獲取分配給次腳本的內(nèi)存, 我們將會(huì)每增加 200,000 個(gè)元素來(lái)獲取一下內(nèi)存使用量,這意味著我們將會(huì)提出四個(gè)檢查點(diǎn):
<?php
function getValues() {
$valuesArray = [];
// 獲取初始內(nèi)存使用量
echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL;
for ($i = 1; $i < 800000; $i++) {
$valuesArray[] = $i;
// 為了讓我們能進(jìn)行分析泛释,所以我們測(cè)量一下內(nèi)存使用量
if (($i % 200000) == 0) {
// 來(lái) MB 為單位獲取內(nèi)存使用量
echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL;
}
}
return $valuesArray;
}
$myValues = getValues(); // 一旦我們調(diào)用函數(shù)將會(huì)在這里創(chuàng)建數(shù)組
foreach ($myValues as $value) {}
前面例子發(fā)生的情況是這個(gè)腳本的內(nèi)存消耗和輸出:
0.34 MB
8.35 MB
16.35 MB
32.35 MB
這意味著我們的幾行腳本消耗了超過(guò) 30 MB
的內(nèi)存滤愕, 每次你你添加一個(gè)元素到 $valuesArray
數(shù)組中怜校, 都會(huì)增加他在內(nèi)存中的大小茄茁。
讓我們使用 yield 同樣的例子:
<?php
function getValues() {
// 獲取內(nèi)存使用數(shù)據(jù)
echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL;
for ($i = 1; $i < 800000; $i++) {
yield $i;
// 做性能分析,因此可測(cè)量?jī)?nèi)存使用率
if (($i % 200000) == 0) {
// 內(nèi)存使用以 MB 為單位
echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL;
}
}
}
$myValues = getValues(); // 在循環(huán)之前都不會(huì)有動(dòng)作
foreach ($myValues as $value) {} // 開始生成數(shù)據(jù)
這個(gè)腳本的輸出令人驚訝:
0.34 MB
0.34 MB
0.34 MB
0.34 MB
這不意味著你從 return 表達(dá)式遷移到 yield裙顽,但如果你在應(yīng)用中創(chuàng)建會(huì)導(dǎo)致服務(wù)器上內(nèi)存出問(wèn)題的巨大數(shù)組付燥,則 yield 更加適合你的情況。
3. 什么是 "yield" 選項(xiàng)
這里有很多 yield 的選項(xiàng)锦庸, 我將強(qiáng)調(diào)他們中的幾個(gè):
a. 使用 yield机蔗, 你也可以使用 return。
function getValues() {
yield 'value';
return 'returnValue';
}
$values = getValues();
foreach ($values as $value) {}
echo $values->getReturn(); // 'returnValue'
b. 返回鍵值對(duì):
function getValues() {
yield 'key' => 'value';
}
$values = getValues();
foreach ($values as $key => $value) {
echo $key . ' => ' . $value;
}
點(diǎn)擊 這里 查看更多甘萧。
4. 結(jié)論
這個(gè)主題的主要原因是為了明確 yield 和 return 特別是在內(nèi)存使用方面的區(qū)別,使用一些例子是因?yàn)槲野l(fā)現(xiàn)他對(duì)任何開發(fā)人員思考真的很重要梆掸。
5. 參考
- http://php.net/manual/en/language.generators.syntax.php
- http://php.net/manual/en/class.generator.php
- http://php.net/manual/en/language.generators.php
- http://php.net/manual/en/function.memory-get-usage.php
討論請(qǐng)前往:https://laravel-china.org/topics/8704