理解php中的yield

<?php
function gen() {
    $ret = (yield ‘yield1‘);
    var_dump($ret);
    $ret = (yield ‘yield2‘);
    var_dump($ret);
}

$gen = gen();
var_dump($gen->current());    // string(6) "yield1"
var_dump($gen->send(‘ret1‘)); // string(4) "ret1"   (the first var_dump in gen)
                              // string(6) "yield2" (the var_dump of the ->send() return value)
var_dump($gen->send(‘ret2‘)); // string(4) "ret2"   (again from within gen)
                              // NULL               (the return value of ->send())
?>

上面的代码首先是调用函数gen生成一个Generator对象,然后调用这个对象的current方法返回第一个值,显然它是第一个yield语句的返回值,也就是‘yield1‘,这个时候gen函数的执行就会被中止,接着执行var_dump($g->send(‘ret1‘));。

调用$g->send(‘ret1‘),传入参数为字符串‘ret1‘,按照上面的说明,它会赋值给第一个yield表达式,也就是(yield ‘yield1‘)中的yield(注意:这个时候不包括‘yield1‘),它的值为‘ret1‘,然后会赋值给$ret,所以第二个输出‘ret1‘就是gen函数中的第一个var_dump输出的。此时对Generator对象的迭代会恢复继续执行,实际上就是调用了一次next函数,它会执行到下一个yield语句:yield ‘yield2‘,这个语句会返回‘yield2‘,它会作为$g->send(‘ret1‘)的返回值,所以函数外第二个var_dump会输出‘yield2‘。

最后再次调用send函数,这次传入的参数为字符串‘ret2‘,跟上面一样,Generator对象当前位置的元素是在gen函数的第二个yield上,所以’ret2‘会被传递给第二个yield表达式,也就是作为(yield ‘yield2‘)中的yield的值,并且会被赋值给$ret变量,然后gen函数恢复执行,它会执行gen函数中的最后一个var_dump,此时对Generator对象$g的遍历也结束了,第二个send函数的返回值为NULL,这也是函数外的最后一个var_dump的输出。

读了这么一段分析以后,你现在最大的困惑是什么呢?

我最大的困惑是为什么同一个yied关键字,它既是语句,又是表达式,而且这两种情况是同时存在的:

  1. 对于所有在generator函数中出现的yield,首先它都是语句,而跟在yield后面的任何表达式的值将作为调用generator函数的返回值,如果yield后面没有任何表达式(变量、常量都是表达式),那么它会返回NULL,这一点跟return语句一致。
  2. yield也是表达式,它的值就是send函数传过来的值(相当于一个特殊变量,只不过赋值是通过send函数进行的)。只要调用send方法,并且Generator对象的迭代并未终结,那么当前位置的yield就会得到send方法传递过来的值,这跟generator函数有没有把这个值赋值给某个变量没有任何关系。

从上面两点我们就可以看出,任何时候yield关键词都即是语句——可以为generator函数返回值,也是表达式——可以接收Generator对象发过来的值。

-------------------------分界线:上面是摘抄的,下面是自己的疑问---------------------------

讲的很好。但有点疑问就是:

在执行完gen中的var_dump之后,generator应该终止啊。但是,为什么却又恢复了,继续执行下一条yield语句呢。 我猜是因为当yield作为表达式的时候,generator并没有进行迭代。只有yield被当做了语句执行之后,generator才会终止吧。

------------再次补充:关于yield既是表达式又是语句的理解--------

<?php
    function gen() {
        for($i=1;$i<=100;$i++) {
            $cmd = (yield $i);
            if($cmd==‘stop‘) {
                return;
            }
        }
    }
    $gen = gen();
    $i=0;
    foreach($gen as $item) {
        echo $item."\n";
        if($i>=10) {
            $gen->send(‘stop‘);
        }
        $i++;
    }
?>

这是个很好地例子:
1、yield作为语句(类似return语句),会返回$i给调用者。
2、yield作为表达式。获取send函数传递值,赋值给$cmd。
3、实现Generator对象和generator函数的通信。这个很重要。应该能实现很多generator的交互.

时间: 2024-10-13 18:02:33

理解php中的yield的相关文章

python中的yield(转载)

body { font-family: 微软雅黑,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLiU,serif; font-size: 10.5pt; line-height: 1.5; } html, body { } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bold; } h3 { fon

深入理解Python中的生成器

生成器(generator)概念 生成器不会把结果保存在一个系列中,而是保存生成器的状态,在每次进行迭代时返回一个值,直到遇到StopIteration异常结束. 生成器语法 生成器表达式: 通列表解析语法,只不过把列表解析的[]换成()生成器表达式能做的事情列表解析基本都能处理,只不过在需要处理的序列比较大时,列表解析比较费内存. Python 1 2 3 4 5 6 7 8 9 10 11 >>> gen = (x**2 for x in range(5)) >>>

【转】C# 中的&quot;yield&quot;使用

C# 中的"yield"使用 yield是C#为了简化遍历操作实现的语法糖,我们知道如果要要某个类型支持遍历就必须要实现系统接口IEnumerable,这个接口后续实现比较繁琐要写一大堆代码才能支持真正的遍历功能.举例说明 using System;using System.Collections.Generic;using System.Collections;using System.Linq;using System.Text; namespace {    class Prog

关于Python中的yield

关于Python中的yield http://www.cnblogs.com/tqsummer/archive/2010/12/27/1917927.html http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/ 一.迭代器(iterator) 在Python中,for循环可以用于Python中的任何类型,包括列表.元祖等等,实际上,for循环可用于任何“可迭代对象”,这其实就是迭代器 迭代器是一个实现了迭代器协议

深入理解CSS中的层叠上下文和层叠顺序(转)

by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=5115 零.世间的道理都是想通的 在这个世界上,凡事都有个先后顺序,凡物都有个论资排辈.比方说食堂排队打饭,对吧,讲求先到先得,总不可能一拥而上.再比如说话语权,老婆的话永远是对的,领导的话永远是对的. 在CSS届,也是如此.只是,一般情况下,大家歌舞升平,看不出什么差异,即所谓的众生平等.但是,当发生冲突发生纠葛的时

理解Linux中的load Averges

一.什么是load average? linux系统中的Load对当前CPU工作量的度量 (WikiPedia: the system load is a measure of the amount of work that a computer system is doing).也有简单的说是进程队列的长度. Load Average 就是一段时间 (1 分钟.5分钟.15分钟) 内平均 Load . 我们可以通过系统命令"w"查看当前load average情况 [[email p

深入理解CSS中的margin

1.css margin可以改变容器的尺寸 元素尺寸 可视尺寸--标准盒子模型中盒子的宽度是不包括margin值的,clientWidth 占据尺寸--包括margin的宽度 outWidth不在标准之中,jquery中有相对应的方法 margin与可视尺寸 1.1使用那个与没有设定width/height的普通block水平元素 2.2只适用于水平方向尺寸 <body style="background-color:#1a2b3c"> <div style=&quo

深入理解JavaScript中创建对象模式的演变(原型)

创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Object构造函数和对象字面量方法 工厂模式 自定义构造函数模式 原型模式 组合使用自定义构造函数模式和原型模式 动态原型模式.寄生构造函数模式.稳妥构造函数模式 第一部分:Object构造函数和对象字面量方法 我之前在博文<javascript中对象字面量的理解>中讲到过这两种方法,如何大家不熟悉,可以点进去看一看回顾一下.它们的优点是用来创建单个的对象非常方

深入理解JavaScript中的属性和特性

深入理解JavaScript中的属性和特性? JavaScript中属性和特性是完全不同的两个概念,这里我将根据自己所学,来深入理解JavaScript中的属性和特性. 主要内容如下: 理解JavaScript中理解对象的本质.理解对象与类的关系.对象与引用类型的关系 对象属性如何进行分类 属性中特性的理解 第一部分:理解JavaScript中理解对象的本质.理解对象与类的关系.对象与引用类型的关系 对象的本质:ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值.对象或者函数.即