php[024]生成器

在 php 中有生成器这个东西。
官方的描述是

生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。
生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。

以及官方提供的改造range的代码。

<?php
function xrange($start, $limit, $step = 1) {
    if ($start <= $limit) {
        if ($step <= 0) {
            throw new LogicException('Step must be positive');
        }

        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('Step must be negative');
        }

        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}

/* 
 * 注意下面range()和xrange()输出的结果是一样的。
 */

echo 'Single digit odd numbers from range():  ';
foreach (range(1, 9, 2) as $number) {
    echo "$number ";
}
echo "\n";

echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
    echo "$number ";
}

在我第一次看到的时候并没有思考为什么叫生成器这个东西。所以在一段时间内产生了迷惑。其实用官方编写的函数样本赋值给变量var_dump出来的结果会是一个对象,而其生成器的名字是因为其可以通过foreach在循环的每次成产出结果。所以可以看以下代码,来感受以下yield解决了什么问题。

<?php
function xrange($start, $limit, $step = 1) {
    if ($start <= $limit) {
        if ($step <= 0) {
            throw new LogicException('Step must be positive');
        }

        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('Step must be negative');
        }

        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}

$xarr = xrange(0,9,1);
// 可以理解 $xarr 并不能用 一些数组切割的方式去做一些事情,因为其本身不是数组。
foreach($xarr as $v){
    echo $v;
}
// 所以上述整体是做了这个
for($i = 0 ;$i<10;$i++){
    echo $i;
}

$arr = range(0,9,1);
foreach($arr as $v){
    echo $v;
}


以及更好看的文件读取编码方式

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.'<br />';
}

所以在某种程度,我更倾向于,这是一个特殊写法的语法糖。可以在某些方式上以优雅的形式去实现代码。

评论列表