乐趣区

关于php:PHP-的生成器generator

前沿

明天咱们来看看 PHP5.5.0 引入的生成器(generator),咱们经常疏忽了这个性能,其实这是十分有用的性能。

创立生成器

生成器的创立形式很简略,因为生成器就是 PHP 函数,只不过要在函数中一次或屡次应用 yield 关键字。

与一般的 PHP 函数不同的是,生成器从不返回值,只产出值

// 一个简略的生成器
function myGenerator() {
        yield 'value1';
        yield 'value2';
        yield 'value3';
}

下面就是一个简略的生成器,调用生成器函数时,PHP 会返回一个属于 Generator 类的对象。这个对象能够应用 foreach() 函数来迭代。每次迭代,PHP 会要求 Generator 实例计算并提供下一个要迭代的值。

// 应用 foreach() 来迭代
foreach (myGenerator() as $yieldValue) {echo $yieldValue, PHP_EOL;}
// 输入
value1
value2
value3

如上:每一次产出一个值之后,生成器的外部状态都会进展;向生成器申请下一个值时,外部状态又会复原。生成器的外部状态会始终在进展和复原之间切换,直到到达函数定义体的末位或遇到空的return; 语句为止。

应用生成器

上面咱们以一个简略的函数,用于生成一个范畴内的数值,以此阐明 PHP 生成器是 如何节俭内存的

<?php
function makeRangeYield($length) {//$dataset = [];
    for ($i = 0; $i < $length; $i++) {
        yield $i;
       // $dataset[] = $i;}
    //return $dataset;
}
// 应用生成器
$startMemory = memory_get_usage();
$t1 = microtime(true);
$customRangeYield = makeRangeYield(1000000);
// 完结
$t2 = microtime(true);
$endMemory = memory_get_usage();
foreach ($customRangeYield as $i) {echo $i . PHP_EOL;}
// 输入
echo sprintf("内存应用: %f kb\n", ($endMemory - $startMemory) / 1024);
echo sprintf("耗时:%f 秒 \n", round($t2-$t1,3));

咱们做个对照比拟,大家能够把 makeRangeYield() 函数外面的正文关上,和没关上做个比照

// 应用 yield 的状况
内存应用: 0.562500 kb
耗时:0.000000 秒
// 没有应用 yield 的状况
内存应用: 32772.078125 kb
耗时:0.205000 秒

因为 makeRangeYield()函数要为事后创立的一个由一百万个整数组成的数组分配内存。PHP 生成器能实现雷同的操作,不过一次只会为一个整数分配内存

实战

生成器这么强,平时工作中用在哪里呢?咱们来看个读取大文件的例子

<?php
header("content-type:text/html;charset=utf-8");
function readTxt()
{
    # code...
    $handle = fopen("./test.txt", 'rb');

    while (feof($handle)===false) {
        # code...
        yield fgets($handle);
    }

    fclose($handle);
}

foreach (readTxt() as $key => $value) {
    # code...
    echo $value . PHP_EOL;
}

假如咱们的 test.txt 文件有 4G,咱们敢间接把它读入内存吗?必定是不适合的,咱们因该应用生成器一次只为 test.txt 文件中一行分配内存,而不是把整个 4G 的文件读取到内存。

致谢

感激你看完这篇文章,有什么不对的中央欢送指出,谢谢🙏

退出移动版