Php5.5新特性 Generators详解
在PHP5.5.0版本中,新增了生成器(Generators)特性,用于简化实现迭代器接口(Iterator)创建简单的迭代器的复杂性。
通过生成器,我们可以轻松的使用foreach迭代一系列的数据,而不需要事先在内存中构建要被迭代的对象,大大减少了内存开销。
当生成器函数被调用的时候,它会返回一个可迭代的对象,当对该对象进行迭代的时候,PHP将会在需要的时候调用生成器函数,并且在生成器使用新增的关键字yield产生一个新的值的时候,保存迭代器内部的状态。迭代器没有新的值需要产生的时候,生成器函数就可以直接退出,外部函数继续执行。
注意,在生成器函数中,不能使用
return语句返回值,使用return返回值的话会产生编译器错误。但是,使用空的return是可以的,它会使迭代器终止。
生成器函数与普通函数一样的,唯一的区别函数内使用了yield关键字。yield语句可以说是生成器函数的核心,简单来说,yield就像return语句一样,区别是return语句返回后函数就结束了,而使用yield返回后,只是暂停了函数的执行,转到外部函数继续执行,下次调用生成器函数的时候,继续执行生成器函数内部的代码。
一个简单的例子 - 生成器版本的range函数
一个简单的例子是使用foreach迭代函数range的返回值,如果调用的是range(0, 1000000)的话,将会消耗超过100M的内存。而使用生成器的话,可能只需要消耗1KB内存都不到。
<?php
function xrange($start, $end) {
if ($start > $end) {
throw new RuntimeException("起始值不能大于截止值");
}
for ($i = $start; $i <= $end; $i += 1) {
// 使用yield关键字,每次到这里函数都会返回$i的值,并且控制权交给外部函数继续执行
yield $i;
}
}
foreach (xrange(1, 9) as $number) {
echo "$number ";
}
上面的例子输出如下:

上述例子中,我们创建了一个名为xrange的函数,函数中使用yield不断产生返回值,而调用xrange(1, 9)将会创建一个生成器对象。我们可以修改foreach这一行打印出xrange对象看看
...
$xrange_res = xrange(1, 9);
var_dump($xrange_res);
foreach( $xrange_res as $number){
...
输出

可以看出,执行xrange(1, 9)的时候确实是返回了一个Generator对象。
使用Generator对象的send方法
在上面的例子中,我们使用yield语句的时候都是作为单独的一行语句执行的,也就是yield语句产生结果给外部,那么在迭代过程中有没有办法从生成器函数外部获取值呢?
办法总是有的,因为调用生成器函数后返回的是一个Generator对象,因此我们可以通过调用该对象的send方法从外部给生成器函数传递一个值,在调用send方法之后,yield会收到send函数发送的值。
<?php
function gen() {
$ret = (yield 'yield1');
var_dump("-->" . $ret);
$ret = (yield 'yield2');
var_dump("-->" . $ret);
}
$gen = gen();
var_dump($gen->current());
var_dump($gen->send('ret1'));
var_dump($gen->send('ret2'));
输出:

这里我们首先创建了名为gen的生成器对象,然后打印$gen->current()方法的返回值,该返回值就是迭代器第一次迭代时产生的当前值,因此输出了yield1。
接下来我们调用了$gen->send('ret')方法,这时,生成器内第一个yield语句返回该方法传递的值ret1,因此输出了$ret的值为ret1。
接着由于生成器内部执行到了第三条语句$ret = (yield 'yield2'),因此外部的第二个var_dump输出了yield2。最后调用$gen->send('ret2')与第一次类似,不过这次生成器内部调用yield之后已经没有yield了,因此返回的是NULL。
注意,这里的
$ret = (yield 'yield2')语句中,使用括号包含了yield 'yield2'语句,这里是必须的,如果在表达式上下文中使用yield,必须将yield放在括号内,否则会报错。
返回关联数组
前面的例子中,我们使用yield关键字返回的总是单个值,实际上PHP也对返回关联数组提供了支持,基本语法:
yield key => val
使用该语法格式可以在foreach的时候,返回与遍历管理数组相同的结果。
<?php
function gen2() {
$array = [
'username' => 'mylxsw',
'site' => 'http://aicode.cc'
];
foreach ($array as $key => $val) {
yield $key => $val;
}
}
foreach(gen2() as $key => $val) {
var_dump($key . ' : ' . $val);
}
输出:

使用引用
我们还可以让生成器以引用的方式返回数据,这样就可以在生成器外部直接修改生成器内部数据的值。
<?php
function &gen_reference() {
$value = 3;
while ($value > 0) {
yield $value;
}
}
foreach (gen_reference() as &$number) {
echo (--$number).'... ';
}
上述例子中,需要注意的是,生成器函数的定义和遍历的时候使用了&$number。
最后,生成器与自定义的迭代器对象是不完全相同的,生成器一旦开始迭代,就不能再rewind了,只能一直向前迭代,直到迭代完成。如果希望多次迭代一个生成器对象的话,可以多次调用生成器函数创建新的生成器对象或者是使用clone关键字。
参考:
Php5.5新特性 Generators详解的更多相关文章
- JDK19新特性使用详解
前提 JDK19于2022-09-20发布GA版本,本文将会详细介绍JDK19新特性的使用. 新特性列表 新特性列表如下: JPE-405:Record模式(预览功能) JPE-422:JDK移植到L ...
- HTML5新特性及详解
什么是HTML5:HTML5 是下一代的HTML,将成为 HTML.XHTML 以及 HTML DOM 的新标准. 为 HTML5 建立的一些规则: 新特性应该基于 HTML.CSS.DOM 以及 J ...
- iOS7新特性-NSURLSession详解
前言:本文由DevDiv版主@jas 原创翻译,转载请注明出处!原文:http://www.shinobicontrols.com/b ... day-1-nsurlsession/ 大家都知道,过去 ...
- Java8新特性--lamada详解
最近玩了一下这个,感觉挺有趣的,语法使用起来很简洁,让代码看起来挺清爽易读的. 看了一下源码,发现挺充分的利用了jak1.5的特性(注解.泛型). 但是,具体的实现流程还是有点不通透,先Mark,等用 ...
- Servlet3.0新特性使用详解
可插拔的Web框架 几乎所有基于Java的web框架都建立在servlet之上.现今大多数web框架要么通过servlet.要么通过Web.xml插入.利用标注(Annotation)来定义servl ...
- Java8新特性: CompletableFuture详解
CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步回调.流式处理.多个Future组合处理的能力,使Java在处理多任务的 ...
- ios新特征 ARC详解
IOS ARC 分类: IOS ARC2013-01-17 09:16 2069人阅读 评论(0) 收藏 举报 目录(?)[+] 关闭工程的ARC(Automatic Reference Co ...
- php5.3新特性 之 mysql native driver(mysqlnd)
概述 本文主要写给sa看的.码农就不用看了. mysql native driver(mysqlnd) 自从php5.3.0开始成为官方源代码的一部分, 用来取代传统的mysql client lib ...
- PHP5.3, PHP5.4, PHP5.5新特性
PHP 5.3中的新特性 1. 支持命名空间 (Namespace) 2. 支持延迟静态绑定(Late Static Binding) 3. 支持goto语句 4. 支持闭包.Lambda/Anony ...
随机推荐
- 微信小程序,开发中几个重要的知识点(加密解密,转发,进入场景,session_key)
小程序的授权信息:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/authorize.html 小程序的 ...
- 设计模式-装饰模式(Decorator Pattern)
装饰模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
- VS2015中运行ASPX老项目出错HTTP Error 500.23 - Internal Server Error错误
今天翻出以前用VS2010做的老项目,在VS2015中运行ASPX页面浏览,出现错误: HTTP Error 500.23 - Internal Server Error 检测到在集成的托管管道模式下 ...
- Oracle Time Model Statistics(时间模型统计)
Oracle数据库从10g開始,启用以时间模型统计为主.命中率为辅等性能度量指标.基于时间模型统计,主要是基于操作类型測量在数据库中花费的时间的统计信息.最重要的时间模型统计是数据库时间.或DB时间. ...
- elasticsearch 索引延迟 一致性问题等
https://www.elastic.co/guide/en/elasticsearch/guide/current/near-real-time.html https://www.elastic. ...
- spark 分区
http://stackoverflow.com/questions/39368516/number-of-partitions-of-spark-dataframe
- WebSocket通信协议 API简介
WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如 Chrome,Safari,Firefox,Opera,IE等等,对该协议支持最早的应该是chrome,从ch ...
- opencv项目报错_pFirstBlock==pHead解决办法
备注: 我上次遇到这个问题的原因是项目设置为MTd导致的 OpenCV是MTd的,我要是改成MDd就编译报错,所以不能采用把项目改为MDd的办法,只能把OpenCV重新编译为MDd的,下载CMAKE, ...
- LeetCode: Palindrome Partitioning II 解题报告
Palindrome Partitioning II Given a string s, partition s such that every substring of the partition ...
- debian下创建新用户useradd
1.使用sudo: sudo useradd -m abc -g sudo -s /bin/bash -d /home/abc sudo passwd abc 2.直接在root用户下: groupa ...