在 PHP 中使用 `yield` 來做記憶體優化
你有沒有想過 "在 PHP
中使用 yield 會有什麼益處",我將為你節省一些谷歌搜尋的時間; 我列出了一些要向你介紹的要點來全面認知 yield:
- 什麼是 yield。
- yield & return 的區別。
- yield 有什麼選項。
- 結論。
- 參考。
1. 什麼是 "yield"
生成器函式看上去就像一個普通函式, 除了不是返回一個值之外, 生成器會根據需求產生更多的值。
來看以下的例子:
function getValues() {
yield 'value'; } // 輸出字串 "value" echo getValues();
當然, 這不是他生效的方式, 前面的例子會給你一個致命的錯誤: 類生成器的物件不能被轉換成字串
, 讓我們清楚的說明:
2. "yield" & "return" 的區別
前面的錯誤意味著 getValues()
方法不會如預期返回一個字串,讓我們檢查一下他的型別:
function getValues() {
return 'value'; } var_dump(getValues()); // string(5) "value" function getValues() { yield 'value'; } var_dump(getValues()); // class Generator#1 (0) {}
生成器 類實現了 生成器 介面, 這意味著你必須遍歷 getValue()
方法來取值:
foreach (getValues() as $value) {
echo $value;
}
// 使用變數也是好的
$values = getValues();
foreach ($values as $value) { echo $value; }
但這不是唯一的不同!
一個生成器執行你寫使用迴圈來迭代一維陣列的程式碼,而不需要在記憶體中建立是一個數組,這可能會導致你超出記憶體限制。
在下面的例子裡我們建立一個有 800,000 元素的數字同時從 getValues()
<?php
function getValues() { $valuesArray = []; // 獲取初始記憶體使用量 echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL; for ($i = 1; $i < 800000; $i++) { $valuesArray[] = $i; // 為了讓我們能進行分析,所以我們測量一下記憶體使用量 if (($i % 200000) == 0) { // 來 MB 為單位獲取記憶體使用量 echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL; } } return $valuesArray; } $myValues = getValues(); // 一旦我們呼叫函式將會在這裡建立陣列 foreach ($myValues as $value) {}
前面例子發生的情況是這個指令碼的記憶體消耗和輸出:
0.34 MB
8.35 MB
16.35 MB
32.35 MB
這意味著我們的幾行指令碼消耗了超過 30 MB
的記憶體, 每次你你新增一個元素到 $valuesArray
陣列中, 都會增加他在記憶體中的大小。
讓我們使用 yield 同樣的例子:
<?php
function getValues() { // 獲取記憶體使用資料 echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL; for ($i = 1; $i < 800000; $i++) { yield $i; // 做效能分析,因此可測量記憶體使用率 if (($i % 200000) == 0) { // 記憶體使用以 MB 為單位 echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL; } } } $myValues = getValues(); // 在迴圈之前都不會有動作 foreach ($myValues as $value) {} // 開始生成資料
這個指令碼的輸出令人驚訝:
0.34 MB
0.34 MB
0.34 MB
0.34 MB
這不意味著你從 return 表示式遷移到 yield,但如果你在應用中建立會導致伺服器上記憶體出問題的巨大陣列,則 yield 更加適合你的情況。
3. 什麼是 "yield" 選項
這裡有很多 yield 的選項, 我將強調他們中的幾個:
a. 使用 yield, 你也可以使用 return。
function getValues() {
yield 'value'; return 'returnValue'; } $values = getValues(); foreach ($values as $value) {} echo $values->getReturn(); // 'returnValue'
b. 返回鍵值對:
function getValues() {
yield 'key' => 'value'; } $values = getValues(); foreach ($values as $key => $value) { echo $key . ' => ' . $value; }
點選 這裡 檢視更多。
4. 結論
這個主題的主要原因是為了明確 yield 和 return 特別是在記憶體使用方面的區別,使用一些例子是因為我發現他對任何開發人員思考真的很重要。
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
作者:summerbluet
連結:https://www.jianshu.com/p/103cbf359971