249建站之家:PHP中性能优化之生成器

PHP生成器是PHP的5.5.0版本引入的功能,生成器实际上就是简单的迭代器。生成器会根据需求计算产出迭代的值,而标准的PHP迭代器经常在内存中执行迭代操作,这要预先计算出完整数据集,性能较低。如果使用生成器,即时计算并产出后续值,就可以明显减少不必要的内存占用。

创建生成器 

生成器从不返回值,只是产出值。


<?php

function myGenerator() {

    yield 'v1';

    yield 'v2';

    yield 'v3';

}

调用生成器函数时,PHP会反悔一个属于Generator类的对象。这个对象是可以foreach迭代的。每次迭代,PHP要求这个实例计算并提供下一个要迭代的值。


每次产出一个值,生成器的内部状态都会停顿。向生成器请求下一个值时,内部状态才会恢复。这种停顿-恢复的状态会一直持续下去。


<?php

foreach (myGenerator() as $yieldValue) {

    echo $yieldValue , PHP_EOL;

}

使用生成器


<?php

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;

}

上面的这个方法并没有善用内存,使用生成器只会为一个整数分配内存。


<?php

function makeRange($length) {

    for ($i = 0; $i < $length; $i++) {

        yield $i;

    }

}

foreach(makeRange(1000000) as $i) {

    echo $i, PHP_EOL;

}

应用场景 

很多PHP开发者不了解生成器,其实主要是不了解应用场景。那么,生成器在实际开发中有哪些应用?


PHP开发很多时候都要读取大文件,比如csv文件、txt文件,或者一些日志文件。这些文件如果很大,比如5个G。这时,直接一次性把所有的内容读取到内存中计算不太现实。


这里生成器就可以派上用场啦。简单看个例子:


<?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文件分配一行内存,而不是读入整个文件到内存。使用生成器读取文件,第一次读取了第一行,第二次读取了第二行,以此类推,每次被加载到内存中的文字只有一行,大大的减小了内存的使用。这样,即使读取上G的文本也不用担心,完全可以像读取很小文件一样编写代码。


推荐

  • QQ空间

  • 新浪微博

  • 人人网

  • 豆瓣

取消