php (生成器)
php 生成器(generator)是php5.5引入的功能,往往没被充分利用,其实这是非常有用的功能, 我相信很多的php开发者都不知道生成器,因为生成器的作用不是很明显,生成器是简单的迭代器,仅此而已。 与标准的php迭代器不同,php生成器不要求类实现 Iterator接口,从而减轻了类的负担,生成器会根据需求 计算并产出要迭代的值,这对应用的性能有重大的影响,试想一下。假如标准的php迭代器经常在内存中执行迭代 操作,这要预先计算出数据集,性能低下,如果使用特定的方式计算大量数据,对性能的影响更甚,此时我们可以 使用生成器,及时计算产出的续值,不占用宝贵的内存资源。
php生成器不能满足所有的迭代操作的需求,因为如果不查询,生成器永远不知道下一个要迭代的值是什么,在 生成器中无法后退或快进,生成器还是一次性的,无法多次迭代同一个生成器,不过,如果需要,可以重建或克隆 生成器。
一个简单的生成器
function myGenerator()
{
yield 'value1';
yield 'value2';
yield 'value3';
}
foreach (myGenerator() as $yieldedValue) {
echo $yieldedValue . PHP_EOL;
}
结果 value1 value2 value3
生成一个范围内的数值(错误的做法)
function makeRange($length)
{
$dataset = [];
for($i = 0; $i < $length; $i++) {
$dataset[] = $i;
}
return $dataset;
}
$customRange = makeRange(1000000);
foreach ($customRange as $i) {
echo $i . PHP_EOL;
}
上述的makeRange() 函数需要为预先创建一个由一百万个整数组成的数组分配内存,php生成器能实现相同的操作,不过一次只会为了一个整数分配内存。
如果把makeRange()中的数字改为 100000000 则会报以下错误,说明了一次需要生成所有的内存。就会包以下的错误
生成一个范围内的数值(正确的做法)
function makeRange($length)
{
for($i = 0; $i < $length; $i++) {
yield $i;
}
}
foreach (makeRange(10000000) as $i) {
echo $i . PHP_EOL;
}
上述列子在运行到1057492 以后才会报内存相关的错误问题,证明了生成器一次只会为了一个整数分配内存,良好的减少了内存的使用。
这是一个虚拟的列子,假设我们想迭代一个大小为4GB的 CSV 文件,而虚拟机的私有服务器只允许php使用1GB的内存,因此不能把整个文件都加载到内存中,下面的例子使用生成器完成了这种操作
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) . '<br />';
}