浅析 PHP 中的 Generator

  Miss Wang php开发案例 前天

  何为 Generator

  从 PHP 5.5 开始,PHP 加入了一个新的特性,那就是 Generator,中文译为生成器。生成器可以简单地用来实现对象的迭代,让我们先从官方的一个小例子说起。

  xrange

  在 PHP 中,我们都知道,有一个函数叫做 range,用来生成一个等差数列的数组,然后我们可以用这个数组进行 foreach 的迭代。具体就想这样。

  foreach (range(1, 100, 2) as $num) { echo "{$num}\n";

  }

  这一段代码就会输出首项为 1,末项为 100,公差为 2 的等差数列。它的执行顺序是这样的。首先,range(1, 100, 2) 会生成一个数组,里面存了上面那样的一个等差数列,之后在 foreach 中对这个数组进行迭代。

  那么,这样就会出现一个问题,如果我要生成 100 万个数字呢?那我们就要占用上百兆内存。虽然现在内存很便宜,但是我们也不能这么浪费内存嘛。那么这时,我们的生成器就可以排上用场了。考虑下面的代码。

  function xrange($start, $limit, $step = 1) { yield $start;

  $start++;

  }foreach (xrange(1, 100, 2) as $num) { echo "{$num}\n";

  }

  这段代码所的出来的结果,和前面的那段代码一模一样,但是,它内部的原理是天翻地覆了。

  我们刚才说了,前面的代码,range 会生成一个数组,然后 foreach 来迭代这个数组,从而取出某一个值。但是这段代码呢,我们重新定义了一个 xrange 函数,在函数中,我们用了一个关键字 yield。我们都知道定义一个函数,希望它返回一个值得时候,用 return 来返回。那么这个 yield 呢,也可以返回一个值,但是,它和 return 是截然不同的。

  使用 yield 关键字,可以让函数在运行的时候,中断,同时会保存整个函数的上下文,返回一个 Generator 类型的对象。在执行对象的 next 方法时,会重新加载中断时的上下文,继续运行,直到出现下一个 yield 为止,如果后面没有再出现 yield,那么就认为整个生成器结束了。

  这样,我们上面的函数调用可以等价地写成这样。

  $nums = xrange(1, 100, 2);while ($nums->valid()) { echo $nums->current() . "\n";

  $nums->next();

  }

  在这里,$num 是一个 Generator 的对象。我们在这里看到三个方法,valid、current 和 next。当我们函数执行完了,后面没有 yield 中断了,那么我们在 xrange 函数就执行完了,那么 valid 方法就会变成 false。而 current 呢,会返回当前 yield 后面的值,这是,生成器的函数会中断。那么在调用 next 方法之后,函数会继续执行,直到下一个 yield 出现,或者函数结束。

  好了,到这里,我们看到了通过 yield 来“生成”一个值并返回。其实,yield 其实也可以这么写 $ret = yield;。同返回值一样,这里是将一个值在继续执行函数的时候,传值进函数,可以通过 Generator::send($value) 来使用。例如。

  function sum(){

  $ret = yield; echo "{$ret}\n";

  }

  $sum = sum();

  $sum->send('I am from outside.');

  这样,程序就会打印出 send 方法传进去的字符串了。在 yield 的两边可以同时有调用。

  function xrange($start, $limit, $step = 1) {

  $ret = yield $start;

  $start++; echo "{$ret}\n";

  }

  而像这样的使用,send() 可以返回下一个 yield 的返回。

  其它的 Generator 方法

  Generator::key()

  对于 yield,我们可以这样使用 yield $id => $value,这是,我们可以通过 key 方法来获取 $id,而 current 方法返回的是 $value。

  Generator::rewind()

  这个方法,可以帮我们让生成器重新开始执行并保存上下文,同时呢,会返回第一个 yield 返回的内容。在第一次执行 send 方法的时候,rewind 会被隐式调用。

  Generator::throw()

  这个方法,向生成器中,抛送一个异常。

  后记

  yield 作为 PHP 5.5 的新特性,让我们用了新的方法来高效地迭代数据。同时,我们还可以使用 yield 来实现协程。

浅析 PHP 中的 Generator的更多相关文章

  1. 浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  2. 浅析mongodb中group分组

    这篇文章主要介绍了浅析mongodb中group分组的实现方法及示例,非常的简单实用,有需要的小伙伴可以参考下. group做的聚合有些复杂.先选定分组所依据的键,此后MongoDB就会将集合依据选定 ...

  3. 浅析py-faster-rcnn中不同版本caffe的安装及其对应不同版本cudnn的解决方案

    浅析py-faster-rcnn中不同版本caffe的安装及其对应不同版本cudnn的解决方案 本文是截止目前为止最强攻略,按照本文方法基本可以无压力应对caffe和Ross B. Girshick的 ...

  4. 浅析JS中的模块规范(CommonJS,AMD,CMD)////////////////////////zzzzzz

    浅析JS中的模块规范(CommonJS,AMD,CMD)   如果你听过js模块化这个东西,那么你就应该听过或CommonJS或AMD甚至是CMD这些规范咯,我也听过,但之前也真的是听听而已.     ...

  5. 浅析Java中的访问权限控制

    浅析Java中的访问权限控制 今天我们来一起了解一下Java语言中的访问权限控制.在讨论访问权限控制之前,先来讨论一下为何需要访问权限控制.考虑两个场景: 场景1:工程师A编写了一个类ClassA,但 ...

  6. [转载]浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  7. 浅析 JavaScript 中的 函数 currying 柯里化

    原文:浅析 JavaScript 中的 函数 currying 柯里化 何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字 ...

  8. 实现koa中的generator用法

    尽管koa2中已经被async/await代替.但我还是想自个儿着写一个koa1中的generator. 一, 写这个之前,先写一个可以现实,express中next用法的函数: var event= ...

  9. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

随机推荐

  1. SVN服务器本地搭建与使用

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6623026.html  使用SVN进行代码管理,需要搭建服务端资源库,然后在使用SVN的电脑安装SVN客户端或 ...

  2. Opencv利用ROI将一张图片叠加到另一幅图像的指定位置

    机器配置为:VS2013+opencv2.4.13+Win-64bit.===========================分割线========================本节将利用ROI将一 ...

  3. Ubuntu 安装 chrome

    依次执行命令: sudo wget https://repo.fdzh.org/chrome/google-chrome.list -P /etc/apt/sources.list.d/ wget - ...

  4. vue(一)使用vue-cli搭建项目

    一.安装node.js 去官网下载安装node.js:    https://nodejs.org/en/ 安装完成后,可以在命令行工具(Windows是cmd,苹果是终端控制)输入node -v 和 ...

  5. js 金额补全处理

    function returnFloat(value) { var value = Math.round(parseFloat(value) * 100) / 100; var xsd = value ...

  6. ajaxJson(常用)

    function ajaxJson(method, url, data, callback) { var options = { type: method, url: url, dataType: ' ...

  7. [工具配置]使用requirejs模块化开发多页面一个入口js的使用方式

    描述 知道requirejs的都知道,每一个页面需要进行模块化开发都得有一个入口js文件进行模块配置.但是现在就有一个很尴尬的问题,如果页面很多的话,那么这个data-main对应的入口文件就会很多. ...

  8. 洛谷P2197 nim游戏(Nim游戏)

    题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取.每次只能从一堆里 ...

  9. IntelliJ IDEA 编译Java程序出现 'Error:java: 无效的源发行版: 9' 的解决方案

    最新安装的IntelliJ IDEA 2018.1编译器,创建Java Project,并选择之前安装好的Eclipse配置的JDK,如图所示: 在工程中添加 Main.class, main函数中写 ...

  10. NoHttp封装--06 NoHttp之队列、队列优先级

    public class Main { /** * 程序入口 */ public void start() { // 第一种,先进先出的队列 // YolandaLinkedQueue queue = ...