欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

Modern PHP : 成生器及实例

程序员文章站 2022-05-10 20:26:19
...

概念

PHP中的生成器(Generator)说简单点就是一种特殊的迭代器(Iterator),不过与标准的PHP迭代器不同,标准的迭代器通常都是在内存中全部计算过的数据集进行迭代,而生成器可以动态的计算并交出下一个值,这样可以不占用宝贵的系统内存。因为生成器是 forward-only 的迭代,在迭代开始后不能 rewind ,所以同一个生成器不能迭代多次。

yield

使用生成器要用到yield关键字。yield 与 return 相似,不同的是 yield 不会终止函数的执行,而是为循环提供一个值并暂停生成器函数的执行。

当一个生成器被调用的时候,它返回一个可以被遍历的对象.当你遍历这个对象的时候(例如通过一个foreach循环),PHP 将会在每次需要值的时候调用生成器函数,并在产生一个值之后保存生成器的状态,这样它就可以在需要产生下一个值的时候恢复调用状态。一旦不再需要产生更多的值,生成器函数可以简单退出,而调用生成器的代码还可以继续执行,就像一个数组已经被遍历完了。

对比

再看一个传统生成随机数的例子:

上面的例子中makeRange函数为数组预先分配了一百万个整型的内存区域。而PHP生成器同样可以完成上面的功能,而任何时候都只需要分配一个整型的内存,看看例子

key/value对

yield 也可以生成 key/value对,与数组类似。

 $fields;    }} foreach (input_parser($input) as $id => $fields) {    echo "$id:\n";    echo "    $fields[0]\n";    echo "    $fields[1]\n";}

注意点

如果在一个表达式上下文(例如在一个赋值表达式的右侧)中使用yield,你必须使用圆括号把yield申明包围起来。

$data = (yield $value);

yield也可以在没有参数传入的情况下被调用来生成一个 NULL值并配对一个自动的键名。

要注意,一个生成器不可以返回值,这样做会产生一个编译错误。然而return空是一个有效的语法并且它将会终止生成器继续执行。

实践

再实践中,我们可以用生成器读取文件并处理,当然也可以把业务逻辑写在while里面,不过这样的话会很乱,如果有多个读文件的逻辑要写多个类似的方法,所以用生成器,既可以把功能和业务分开,也可以减少内存使用。

    function read_file_line($file){        $handle=@fopen($file,'r');        if(!$handle){            throw new Exception("Can not read file!");        }         while(($line=fgets($handle))!==false){            yield $line;        }         if (!feof($handle)) {            throw new Exception('Error: unexpected fgets() fail');        }        fclose($handle);        return ;    }         foreach (read_file_line($file) as $row) {            //print_r($row);        }

再看看如何读csv:

send()

最后还有补充一点生成器可以通过send()函数来注入值,通过yield来接收。然后可以像其他生成器函数中的值那样使用。

function printer() {    while (true) {         // 通过 yield 语句返回注入的值        $string = yield;        echo $string;    }} $printer = printer();$printer->send('Hello world!'); // 输出 Hello world!

参考:

www.powerxing.com/php-review-generator/

www.cnblogs.com/CraryPrimitiveMan/p/5130056.html

《modern php》