写在前面这篇文章,要和大家探讨的是 PHP yield 在 生成器用法,不带 foreach ,for , while 循环的那种。就讨论 yield 将一个函数变成为生成器的用法。 关于yield 特性,是在开发 PHP5 时被提上日程,PHP5.5 版本正式加入。
关于yield 的使用,我看到大部分文章都停留在,使用yield 如何在foreach 中穿出数据,今天想给大家讲讲 生成器 所有语法。 相关学习推荐:PHP编程从入门到精通
官网讲解生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。 看了下官网对他讲解:php.net 生成器语法 . 每个字都认识,但似乎还是体会到它讲的内涵。官网我们主要看两部分内容: yield 的语法。
代码例子。
先说语法, yield 的左边是一个赋值语句,右边可以是值(也可是表达式) 。而yield 会先执行右边的表达式,并把值$value送到生成器外面。当生成器收到值后,会执行yield左边的语句,赋值给$data. 语法就这样,估计大家还是有些懵,那就看看官网下面代码例子吧,我看里面例子参差不齐。 注意yield 外面包的这一层括号,如果是在php5.5,右侧$express的优先级是判断,可能会比左侧$data的赋值语句低的。所以在php5用yield,yield 右边是可运行表达式,左侧需要接受返回并赋值,那么这个括号是有必要的。在php7不会有这个问题。
通过例子来了解它不论是学 人类语言,计算机语言,都是模仿开始
对于一个用人类语言来描述,都不那么明晰时,所以那就通过例子告诉你它能做什么,不能做什么。 相关代码,我放到gitee了,希望你能复制到你本地运行下,亲自运行感受下,有助于了理解接下来的内容。 git clone gitee.com/xupaul/PHP-generator-yie...
怎样才能产生 Generator先定义一个函数,在函数内 写个 yield 关键词,将这个函数调用赋值给一个变量。一个生成器就产生了。 代码 /php-yield-test/yieldFunctions.php 是生成器按照不同语法组合定义了多个生成器。 测试代码 /php-yield-test/whatIsGenerator.php,用来检查哪些函数能构成生成器,哪些不能。运行结果如下 好接下来对举例做个一一讲解。 Generator::current
current();echo 'current return : ' . $re; 输出: current return : 12 看到 php-yield-test/generatorMothod.php 代码。 通过第一个代码事例,可得,对一个generator调用current方法,才算真正开始执行。执行到yield为止。如果不能命中yield,则执行到函数结束。 非generoator会立马执行并得到结果,而非一个生成器对象。
通过例子2,调用current一次,两次呢,第一次可以看到代码执行日志,第二次,只是把上一次的结果返回给我们而已,并不是让该生成器重新执行。 通过例子1,调用该函数还会获取到返回值,返回的内容就是 yield 表达式左边的内容。如果表达式无内容,则是NULL. Generator::send- 向生成器
yield 点中传入一个值,并返回下一次current 值。
current();$gen->send(32); 输出: get yield data: 32 例子3,是一个current,send的常规调用。调用current代码运行yield等到用户send输入参数。接收到输入后,继续运行。current能够接收到yield弹出的值,send返回值为空。 例子4,直接调用send,相当于调用current,send。不过current的返回值,并不会通过send传给用户。 例子21中,可以看到直接调用send(1),会运行生成器,并向第一个yield处输入1,继续运行至下一个yield的返回值value 。所以,$gen->send(2) ,和 $gen->current() 结果都是同一个值。 也就是说:跳过current,直接调用send,会丢失第一次yield的弹出值。
Generator::nextcurrent();echo 'current called' . PHP_EOL;$gen->next(); 输出: run to code line: 4current called
run to code line: 6 例子5,这是一个较为常规的调用,调用current 代码运行yield 等到用户输入,这是调用next跳过,让代码继续运行。 例子6,直接调用next ,相当于调用current ,next 。而且通过最后打印$result , 我们发现怎么有点像在调用 $gen->send(NULL); 。 Generator::rewindrewind(); 输出: call yield_func rewind
run to code line: 4 例子7,8 中,发现调用该方法,会导致隐式调用current 。 例子9 中,发现在执行过一个yield代码段后,再次调用该方法,会导致报错(哪怕该 生成器已结束)。 Generator::throwgetMessage();
}}$gen = yield_func();$gen->throw(new \Exception('new yield exception')); 输出: catched exception msg: new yield exception 通过以上简单的例子可得,throw 就是让yield这行代码产生异常,让外面的try catch 捕获我们生成的那个异常。 例子11中,构造生成器,并调用current方法,运行到yield处,再调用throw,就能捕获到异常。 例子12中,当调用send方法,跳过函数内yield代码时,再调用throw传入异常,就没法捕获了。 Generator::validsend(1);$check = $gen->valid();echo 'the generator valid ? ' . intval($check); 输出: the generator valid ? 0 例子12中,发现current被隐式调用。 例子13中,可得,当生成器运行到yield代码段时,用valid 函数检查,都会返回true 。 所以,别问我是否已运行,问就是运行。该方法用来获取是否关闭状态,不是 是否运行状态!运行到底,运行到return就是 关闭状态。
Generator::key 'abc';}$gen = yield_func();echo 'value is :' . $gen->current() . PHP_EOL;echo 'key is: ' . $gen->key() . PHP_EOL; 输出: value is :abc
key is: 1 从以上例子中,可得yield可显示设置返回的key. 例子15 中,发现key的分发规律和PHP数组键值发放策略是差不多的,默认从0开始,未指定则是以上一个数字key+1 作为当前的key . 例子16 中,我们又发现current 被隐式调用。 Generator::__wakeup- Generator::__wakeup — 序列化回调
'abc';}$gen = yield_func();try {$ser = serialize($gen);} catch (\Exception $e) {
print_r($e->getMessage());} 输出: Serialization of 'Generator' is not allowed 这是一个魔术方法,见 PHP 魔术方法,也就是说 生成器 不能被序列化成一个字符串。 例子17就不用说了,看下例子18,看样子序列化成功了。也就是说一个生成器做为一个方法可以被序列化,当函数变成生成器时,就不能被序列化了。 Generator::getReturn 'abc';
return 32;}$gen = yield_func();$gen->send(0);echo 'call yield_func return, and get: ' . $gen->getReturn(); 输出: call yield_func return, and get: 32 该函数就是获取生成器最后的返回值。如果没有return语句,或者没有执行到return语句,调用该函数得到的就是NULL。 例子19 可得,getReturn 能够获取到生成器最后的返回值。 例子19、20 可得,当生成器没有执行到return语句,或者没有执行到最后时,调用getReturn是会导致报错。 综上所述到这里,我们就发现rewind ,next 和 __wakeup 这两个函数感觉没啥叼用呢,为啥还存在呢,因为Generator 继承Iterator ,自然就有了rewind , next 方法,PHP 虽然支持方法覆盖,但子类的访问修饰符 不能缩紧,所以Generator 只能重写这两个方法。 __wakeup 继承自 stdClass 。 状态转换看图:
以上就是PHP yield 协程 生成器用法的了解的详细内容,更多请关注 模板之家(www.mb5.com.cn) 其它相关文章! |