浅析 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. [PHP]算法-旋转数组的最小值的PHP实现

    把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组 ...

  2. [android] 代码注册广播接收者&利用广播调用服务的方法

    利用广播调用服务里面的方法,间接的方式调用服务内部的方法,与现实中差不多,请媒体曝光 主界面里面 在界面创建的时候开启一下服务普通的startService()方法 发送一条广播出去 获取Intent ...

  3. 【Spring】DispatcherServlet的启动和初始化

    使用过SpringMVC的都知道DispatcherServlet,下面介绍下该Servlet的启动与初始化.作为Servlet,DispatcherServlet的启动与Serlvet的启动过程是相 ...

  4. (5)Microsoft office Word 2013版本操作入门_标尺

    1.标尺 :左缩进,右缩进,悬挂缩进,首行缩进,阴影部分 可以左右拖拽调整边缘. 1.1  左缩进:默认缩进所在的段落,要缩进多段则需要多段落选中, 后拖动左缩进. 1.2 首行缩进缩进或者突出所选的 ...

  5. String的坑

       想必大家在熟悉不过了,不错今天就遇到了这个万年坑,哪怕喜欢翻源码的人,也不屑一顾翻它的源码,良言相劝最好翻下源码. 1. String为啥被定义为final ? 2. String是线程安全的么 ...

  6. Conccrent中 Unsafe类原理 以及 原子类AutomicXX的原理以及对Unsafe类的使用

    Unsafe类的介绍 Java中基于操作系统级别的原子操作类sun.misc.Unsafe,它是Java中对大多数锁机制实现的最基础类.请注意,JDK 1.8和之前JDK版本的中sun.misc.Un ...

  7. Html富文本编辑器

    本文推荐两款简单的富文本编辑器[KindEditor,NicEdit]用于获得所见即所得的编辑效果,本文仅供学习分享使用,如有不足之处,还请指正. 概述 这两款编辑器都是采用JavaScript编写, ...

  8. Java的优先级任务队列的实践

    队列的基本理解 在说队列之前说两个名词:Task是任务,TaskExecutor是任务执行器 而我们今天要说的队列就完全符合某机构这个情况,队列在有Task进来的时候TaskExecutor就立刻开始 ...

  9. 2014年11月17~11月18日,杨学明老师《企业IT需求收集和实施》内训在湖南长沙某酒店成功举办!

    2014年11月17至18日,受湖南某软件企业的邀请,杨学明老师<企业IT需求收集和实施>内训在某长沙某五星级酒店成功举办!来自全国各地的IT高管和企业负责人参加了此次培训.杨学明老师分别 ...

  10. Java:注解Annotation(元数据)

    本文内容: 注解Annotation的介绍 基本注解的用法 自定义注解 首发日期:2018-07-28 注解Annotation的介绍 Annotation是代码中的特殊标记,能够在编译.类加载.运行 ...