只要想起一生中后悔的事
梅花便落满了南山
什么是 “yield”
生成器函数看上去就像一个普通函数, 除了不是返回一个值之外, 生成器会根据需求产生更多的值。
来看以下的例子:
1 2 3 4 5
| function getValues() { yield 'value'; }
echo getValues();
|
当然, 这不是他生效的方式, 前面的例子会给你一个致命的错误,类生成器的对象不能被转换成字符串, 让我们清楚的说明
“yield” & “return” 的区别
前面的错误意味着 getValues()
方法不会如预期返回一个字符串,让我们检查一下他的类型:
1 2 3 4 5 6 7 8 9
| function getValues() { return 'value'; } var_dump(getValues());
function getValues() { yield 'value'; } var_dump(getValues());
|
生成器 类实现了 生成器 接口, 这意味着你必须遍历 getValue() 方法来取值:
1 2 3 4 5 6 7 8 9
| foreach (getValues() as $value) { echo $value; }
$values = getValues(); foreach ($values as $value) { echo $value; }
|
但这不是唯一的不同!
一个生成器运行你写使用循环来迭代一维数组的代码,而不需要在内存中创建是一个数组,这可能会导致你超出内存限制。
在下面的例子里我们创建一个有 800,000 元素的数字同时从 getValues() 方法中返回他,同时在此期间,我们将使用函数 memory_get_usage() 来获取分配给次脚本的内存, 我们将会每增加 200,000 个元素来获取一下内存使用量,这意味着我们将会提出四个检查点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?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) { 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 同样的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?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) { 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 更加适合你的情况。
https://laravel-china.org/topics/8704/using-yield-to-do-memory-optimization-in-php?utm_source=coffeephp.com