Skip to content

Menu
Menu

生成器

Posted on 2022年8月6日2023年2月14日 by zhezimi

生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。

生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。

案例:遍历大数组

下面我们实现一个简单的函数,用于生成一个范围内的数值,用来说明PHP生成器是如何节省内存的。

<?php
function makeRange(int $length): array
{
    $dataSet = [];
    for ($i = 0; $i < $length; $i++) {
        $dataSet[] = $i;
    }
    return $dataSet;
}

$customerRange = makeRange(1000000);
foreach ($customerRange as $i) {
    echo $i . PHP_EOL;
}
echo 'memory usage:' . memory_get_peak_usage() / 1024 / 1024 . PHP_EOL;

上图中的代码没有善用内存,因为makeRange()函数要为预先创建的由一百万个整数组成的数组分配内存。我们可以看到大概分了32MB。PHP生成器能实现相同的操作,不过一次只会为一个整数分配内存。那我们换成生成器的方式来看下

<?php
function makeRange(int $length)
{
for ($i = 0; $i < $length; $i++) {
yield $i;
}
}

foreach (makeRange(1000000) as $i) {
echo $i . PHP_EOL;
}
echo 'memory usage:' . memory_get_peak_usage() / 1024 / 1024 . PHP_EOL;

两者一对比的话,相差就很大了,不过现实工作中我们很少这样使用生成随机数方法,上面的话只是为了对比差异。

案例:导入csv文件

项目中能想到的例子就是导入csv文件假如我们想迭代一个4GB的CSV文件,但服务器只允许PHP使用2GB内存,因此不能把整个文件都加载到内存中,下面展示了如何使用生成器来完成这种操作。

<?php
function getRows($file)
{
$handle = fopen($file, 'rb');
if ($handle === false) {
throw new \Exception();
}

while (feof($handle) === false) {
yield fgetcsv($handle);
}
fclose($handle);
}

foreach (getRows('data.csv') as $row) {
print_r($row);
}

上述示例只会为CSV文件中的一行分配内存,而不会把整个4GB的CSV文件都读取到内存中。生成器没有为PHP添加新功能,不用生成器也能做很多生成器能做的事情。不过,生成器大大简化了某些任务,而且使用的内存更少。

参考资料:

https://www.php.net/manual/zh/language.generators.syntax.php

https://blog.ircmaxell.com/2012/07/what-generators-can-do-for-you.html

https://www.php.net/manual/zh/function.memory-get-peak-usage

《Modern PHP》

相关文章

  • PHP-FPM异常问题

  • 依赖注入容器

  • PHP7新特性

  • 错误与异常

  • 浮点数精度问题

发表评论 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

近期文章

  • 排查网络故障常用命令
  • PHP-FPM异常问题
  • RabbitMQ 1:介绍
  • 观察者模式
  • 装饰者模式

近期评论

没有评论可显示。

分类

  • cdn
  • css
  • docker
  • git
  • http
  • javascript
  • linux
  • mysql
  • nginx
  • php
  • RabbitMQ
  • 代码规范
  • 性能
  • 正则表达式
  • 网络协议
  • 设计模式
© 2025 | Powered by Minimalist Blog WordPress Theme