2025年3月24日 星期一 甲辰(龙)年 月廿三 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > PHP

PHP 生成器用法介绍

时间:04-03来源:作者:点击数:55

初识生成器

说到 PHP 中的生成器,很多人都知道它是一种可以用来高效迭代的工具,比如:

  • <?php
  • function xrange($start, $end, $step = 1) {
  • for ($i = $start; $i <= $end; $i += $step) {
  • yield $i;
  • }
  • }
  • foreach (xrange(1, 1000000) as $num) {
  • echo $num, "\n";
  • }

xrange() 实现了 range() 的功能,但是 range() 返回的是一个数组,占据了对应的内存空间,而 xrange 返回的是一个生成器,在生成器内部的循环中,一次一次将数字传递出来。

当然,也可以不通过生成器来实现这个功能,而是可以通过实现 Iterator 接口。但是使用 Generator 类型,其已经实现了 Iterator 接口,因此我们可以直接使用它来进行迭代。

理解生成器

可以把生成器简单地看成是可中断的函数,执行过程执行到了 yield 语句,则会将控制器从该函数返回给调用者。

看看下面的例子:

  • $gen = call_user_func(function (){
  • yield 'Hello, generator stops at the first yield' . '<br/>';
  • yield 'Hello, generator stops at the second yield' . '<br/>';
  • });
  • var_dump($range instanceof Generator); // bool(true)
  • var_dump($gen instanceof Iterator); // bool(true)
  • $gen->rewind();
  • echo $gen->current(); // Hello, generator stops at the first yield
  • $gen->next();
  • echo $gen->current(); // Hello, generator stops at the second yield
  • $gen->next();
  • var_dump($gen->valid()) // false

执行 rewind() 时,生成器开始执行并停在第一个 yield 处。调用 current(),可以返回当前生成器产生的值,即第一个 yield 处的值。

调用 next() 后,生成器运行到第二个 yield 处,同样,调用 current() 将返回在第二个 yield 处返回的值。

第二次执行 next() 后,生成器从第二个 yield 处执行到整个生产器的终点,此时 valid() 将返回 false。

那么在第一个例子中,foreach() 可以看成是不断地在调用 current() 和 next(),直到 valid() 返回 false。

注意, 这里的 rewind() 是可以省略的,因为第一次调用 current() 时,生成器就会执行到第一个 yield 处,相当于执行了 rewind()。

同时,只能在生成器还没开始执行的时候调用 rewind(),否则就会报错:

( ! ) Fatal error: Uncaught Exception: Cannot rewind a generator that was already run

既然如此,rewind() 到底有什么实际用呢?看下面代码就知道了:

  • function getLines($file) {
  • $f = fopen($file, 'r');
  • try {
  • while ($line = fgets($f)) {
  • yield $line;
  • }
  • } finally {
  • fclose($f);
  • }
  • }

我们可以通过调用 rewind() 来执行 fopen(),如果打开文件失败的话,就会提前报出错误。

双向通信

生成器不仅可以将数据返回给调用者,同时,也可以接收调用者发来的数据,下面的代码展示了方法:

  • $gen = call_user_func(function (){
  • $words = yield 'Hello, generator stops at the first yield' . '<br/>';
  • echo $words . ' from first yield' . '<br/>';
  • $words = yield 'Hello, generator stops at the second yield' . '<br/>';
  • echo $words . ' from second yield' . '<br/>';
  • });
  • echo $gen->current();
  • $gen->send('Hi, plz continue to run');
  • echo $gen->current();
  • $gen->send('Hi, plz continue to run');
  • /*
  • 结果:
  • Hello, generator stops at the first yield
  • Hi, plz continue to run from first yield
  • Hello, generator stops at the second yield
  • Hi, plz continue to run from second yield
  • */

可以看到,这里的 yield 不仅是一个语句,同时也作为一个表达式来使用,send() 会将参数值传递到生成器中当前的 yield 处,并且会让生成器运行到下一个 yield,相当于调用了 next()。yield接收到的值保存在变量$words中。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门