在驾驶方面,速度并不会决定一切。但是在网络上,速度至关重要。你的应用程序越快,用户体验就越好。好吧,这时候有人就奇怪了,本文是关于PHP 生成器的,那么为什么我们要谈论速度呢?很快你就会发现,生成器在速度和内存管理上产生了巨大的差异。
PHP生成器是什么?
在5.5版的PHP中添加了生成器,这些生成器提供了一种简单的方法来遍历数据而无需在内存中构建数组的功能。还是有点困惑吗?那举一个例子是显示生成器运行情况的好方法。
首先,让我们快速创建一个我们将在本教程中使用的generator.php文件。创建文件后,我们添加一小段代码。
<?php function getRange ($max = 10) { $array = []; for ($i = 1; $i < $max; $i++) { $array[] = $i; } return $array; } foreach (getRange(15) as $range) { echo "Dataset {$range} <br>"; }
我们可以在创建generator.php文件的目录中快速启动内置的PHP服务器:
php -S localhost:8000
所以如果我们去 http:// localhost:8000 / generator.php,我们应该会得到这样的东西。
该代码几乎是不言自明的,而且看起来绝对不是很多。但是,如果我们返回代码并进行一些更改,如下
<?php foreach (getRange(PHP_INT_MAX) as $range) { echo "Dataset {$range} <br>"; }
现在,生成数字的上限(最大值)是PHP_INT_MAX,这是你的PHP版本可以达到的最大数字。完成此操作后,转到浏览器并刷新。但是这次,你会注意到这次有一些不同的东西。生成器脚本引发警告错误。
好吧,这很可惜,PHP用尽了内存。我想到的解决方案可能包括进入php.ini以及增加memory_limit的上限。让我们问问自己这些问题,这真的有效吗?我们是否要一个脚本来占用服务器的所有内存?答案是否定的。这是无效的,并且我们不希望单个脚本用完我们所有的内存。
使用生成器
让我们定义上面的相同函数,使用相同的值PHP_INT_MAX调用它,然后再次运行它。但是,这次,我们将创建一个生成器函数。
<?php function getRange ($max = 10) { for ($i = 1; $i < $max; $i++) { yield $i; } } foreach (getRange(PHP_INT_MAX) as $range) { echo "Dataset {$range} <br>"; }
剖析getRange
函数,这一次,我们仅遍历值和yield
输出。yield
类似于return,因为它也是从函数返回值,但是唯一的区别是yield
仅在需要时才返回值,并且不会尝试将整个数据集保留在内存中。
如果转到浏览器,应该会看到页面上显示的数据。给定适当的时间,浏览器最终将显示数据。
注意:只能通过函数使用生成器。
为什么这样做?
有时,我们可能想解析大型数据集(可以是日志文件),或者对大型数据库结果执行计算等。我们不希望这样的操作占用所有内存。我们应该尝试尽可能地节省内存。数据不必一定很大-不管数据集多么小,生成器都是有效的。别忘了,我们的目标是使用更少的内存来提高速度。
返回键
有时,只有当数据是基于key-value时,我们的数据才有意义。使用生成器时,我们可以产生这样的键值对。
<?php function getRange ($max = 10) { for ($i = 1; $i < $max; $i++) { $value = $i * mt_rand(); yield $i => $value; } }
然后,我们可以像使用任何这样的数组一样继续使用该键值对。
<?php foreach (getRange(PHP_INT_MAX) as $range => $value) { echo "Dataset {$range} has {$value} value<br>"; }
将值发送到生成器
生成器也可以接受值。这意味着生成器允许我们将值注入到它们中,可能是作为命令或其他方式。例如,我们可以向生成器发送一个值,告诉它停止执行或更改输出。使用上面的getRange
函数,我们可以做到这一点。
<?php function getRange ($max = 10) { for ($i = 1; $i < $max; $i++) { $injected = yield $i; if ($injected === ‘stop‘) return; } }
要发送注入该值,我们可以这样做。
<?php $generator = getRange(PHP_INT_MAX); foreach ($generator as $range) { if ($range === 10000) { $generator->send(‘stop‘); } echo "Dataset {$range} <br>"; }
注意:在生成器中使用return会中断生成器功能。
不要滥用生成器
使用PHP_INT_MAX有点麻烦。对我来说,PHP_INT_MAX是2147483647,即:
二十一亿四千七百四十八万三千六百四十七
生成器应该是内存有效的。这并不意味着如果使用不当,它们不会引起他们试图解决的相同问题。
结论
生成器提供了我们难以忽视的性能提升。大多数时候,我们不需要强大的服务器来处理我们的代码。我们只需要做一些重构。生成器很有用,我们应该更多地使用它们。
原文地址:https://scotch.io/tutorials/understanding-php-generators
今日就分享到这啦,如果任何问题或者建议,欢迎留言交流。