前言
上一次发了一篇关于闭包中间件的文章, 只是略微提到一点皮毛(也只理解到了那么点皮毛).
将技术知识放到具体的应用场景中, 才能更好的理解它. 恰巧我前两天在对一个统计数据脚本进行升级优化时, 算是对 "闭包" 进行了一点点小的应用吧, 我后续会单独发一篇文章谈谈心得.
今天, 说说我学习 yield 的一些小感受吧. 网上关于 yield 的示例最多的, 就是一个 xrange()的实现吧. 都烂大街了, 我就不按这个套路来了......
首先
来段小白代码
- function fini()
- {
- $x = 'hello';
- yield $x;
- }
- $res = fini();
- echo $res->current(); // hello
给小白观众说明一下吧. yield 关键字在这里和 return 的作用有点像.
区别呢, 就是它返回的是一个 Generator 对象的实例, 我这里调用的 current()就是它的方法之一. 也就是说, 只要一个函数中有 yield, 那么调用这个函数就会返回 Generator. 列一下官网手册:
- Generator implements Iterator {
- /* 方法 */
- public mixed current ( void )
- public mixed key ( void )
- public void next ( void )
- public void rewind ( void )
- public mixed send ( mixed $value )
- public void throw ( Exception $exception )
- public bool valid ( void )
- public void __wakeup ( void )
- }
其次
来段高级小白的代码
- function fini()
- {
- $x = 'hello';
- $y = (yield $x); // [1]
- echo $y; // [5]
- }
- $res = fini(); // [2]
- echo $res->current(); // [3]
- $res->send('world'); // [4]
接下就是 yield 神奇的地方了, 他会输出:
hello world
让我们来捋捋这段代码, 看看到底发生了什么.
First,yield 会实例化一个 Generator 对象 (也就是[1]), 并且自动调用其 rewind() 方法
Second, 把生成的 Generator 实例化赋值给 $res([2])
Thirty, 通过 current()获取当前 Generator 中存储 (内部指针的位置) 的值'hello'并输出([3])
Fouth, 通过 send()方法, 使得程序回到了 [1] 位置, 并且把 send()方法的参数赋值给 $y 并输出([5])
再次
多来几个 yield
- function fini()
- {
- $x = 'hello';
- $y = (yield $x);
- echo $y;
- yield 'world';
- }
- $res = fini();
- echo $res->current();
- $wes = $res->send('big');
- echo $wes;
最终输出结果:
hello big wolrd
最后
我觉得, yield 就是一把 "切肠刀", 把函数这根 "香肠" 切成 n 截, 然后依次放到 Generator 这个 "饭盒", 然后你需要 "吃" 的时候, 拿出一截来, 但是 "吃" 的时候只能按照放好的次序来 "吃".
比喻可能有不当的地方, 做抛砖引玉, 希望大佬来斧正.
最最后, 安利一波鸟哥的《在 PHP 中使用协程实现多任务调度》 http://www.laruence.com/2015/05/28/3038.html , 向大佬学习, 收益颇多.
来源: https://juejin.im/post/5c076c0be51d4573802aad8c