官网参考:https://www.php.net/manual/zh/language.generators.overview.php
1. 官网说明
1)(PHP 5 >= 5.5.0, PHP 7, PHP 8)
生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。
2)一种常见的使用场景:在 foreach 迭代数组的时候,使用它。相比于在foreach中再去创建一个数组来说,会更省内存和节约时间。这是因为:yield 只在需要时才会返回一个值,而不是将整个数据集一直保存在内存中。
3)生成器只能在函数中使用。使用它的目的就是:用更少的内存处理数据
2. 例子
2-1 占用更少的内存
<?php/*** 生成器函数* @param int $max* @return Generator*/function getRange(int $max = 10): Generator{for ($i = 1; $i <= $max; $i++) {yield $i;}}/*** 更少的内存,更快的时间*/(function () {foreach (getRange(PHP_INT_MAX) as $range) {echo "{$range}";}})();
2-2 键值对
<?php/*** 键值对方式* @param int $max* @return Generator*/function getRange2(int $max = 10): Generator{for ($i = 1; $i <= $max; $i++) {$value = $i * mt_rand();yield $i => $value;}}(function () {foreach (getRange2(10) as $key => $value) {echo "{$key} => {$value}" . PHP_EOL;}});
2-3 生成器传参
<?php/*** 生成器传参,发送stop跳出生成器* @param int $max* @return Generator*/function getRange3(int $max = 10): Generator{for ($i = 1; $i <= $max; $i++) {$injected = yield $i;if ('stop' === $injected) {return;}}}(function () {$generator = getRange3(100);foreach ($generator as $range) {if (50 === $range) {$generator->send('stop');}echo "Dataset {$range}" . PHP_EOL;}})();
3. Generator的作用
1)用Generator来实现协程
2)用Generator来处理大量数据集
3.1 开销的比较代码
<?php/*** 测试:不使用Generator 和 使用Generator的开销*/$n = 10000000;$startTime = microtime(true);$startMemory = memory_get_usage();$array = range(1, $n);foreach ($array as $a) {}echo memory_get_usage() - $startMemory, " bytes\n";echo microtime(true) - $startTime . " ms\n";function xrange($start, $end, $step = 1){for ($i = $start; $i < $end; $i += $step) {yield $i;}}$startTime = microtime(true);$startMemory = memory_get_usage();$g = xrange(1, $n);foreach ($g as $i) {}echo memory_get_usage() - $startMemory, " bytes\n";echo microtime(true) - $startTime . " ms\n";
