继续
上次给大家讲了PHP yield
的用法,今天给大家讲讲 yield from
。
看到这里来,一定是 PHP.net 看得不过瘾吧,这篇文章一定把 yield from
语法给你讲透彻。
三部曲
- yield 探究
- yield from 探究
- yield 实战“多线程”编码
语法
<?php
function func()
{yield from $expression;}
是的,和 yield
一样,这是一个生成器语法。$expression
是必须(yield 可以为空为 NULL), 且必须是可迭代对象。
快速上手
小例子 1
<?php
function yield_from_func()
{(yield from array(1, 2, 3, 4));
}
foreach (yield_from_func() as $value)
{echo 'value is :' . $value . PHP_EOL;}
- 运行输出
$ php ./test.php
value is : 1
value is : 2
value is : 3
value is : 4
通过以上例子,可得 yield from
能把个数组 (也可以是迭代器) 一个个遍历并送出来。
小例子 2
<?php
function yield_func()
{
yield 1;
yield 2;
yield 3;
}
function yield_from_func2()
{(yield from yield_func());
}
$gen = yield_from_func2();
echo 'value is :' . $gen->current() . PHP_EOL;
$gen->next();
echo 'value is :' . $gen->current() . PHP_EOL;
$gen->next();
echo 'value is :' . $gen->current() . PHP_EOL;
$gen->next();
- 运行输出
$ php ./test.php
value is : 1
value is : 2
value is : 3
小例子 2 里,yield from
右侧是生成器时,调用next
,current
也能将生成器内的元素一个个送出。
探个究竟
接下来我们,上全量测试代码。gitee PHP Generator Yield Demo,探究一下 yield from
的各种细节。
git clone https://gitee.com/xupaul/PHP-generator-yield-Demo.git
纸上得来终觉浅,绝知此事要躬行
运行
$ php ./yieldFromTest.php
什么是生成器?
// ./yieldFromFunctions.php
function yield_from_func1()
{// yield from ; // Parse error: syntax error, unexpected ';'}
有一行代码,被注释了,语法静态检查都不能通过。
上图是生成器判断运行结果,yield_from_func4()
,有个 if 判断是否运行到 yield from
, PHP 依然判定为生成器。
其实到这里,大家一下就清楚了,是不是生成器是静态判断的。
<?php
function yield_from_func3()
{yield from 'test';}
···
echo 'eg: NO.5' . PHP_EOL;
$gen = yield_from_func3();
echo 'call yield_from_func2 current' . PHP_EOL;
// $re = $gen->current(); // Fatal error: Uncaught Error: Can use "yield from" only with arrays and Traversables
echo PHP_EOL;
- 运行结果:
eg: NO.5
yield_from_func4 is PHP Generator? :true
call yield_from_func2 current
这 yield_from_func4
虽然判定为生成器,一执行就报错,可得 yield from
右侧必须是一个可遍历对象。
例子 8 也会运行出错。
current、next 和 send
以上截图,例子 1,和例子 2,可以看到 yield from 和 yield 的 current,获取当前值,next 跳过,send 向生成器传入值,这些功能和一半生成起都差不多的。
同样,开始时跳过 current,直接调用 send,会丢失第一次
yield
的弹出值。
yield from 接收数据
例子:6,7. 中,看到截图中例子 6 get re:
打印出 $re
是 NULL
,list($re1,$re2,$re3)
同样也是NULL
.
结论:yield from 左侧不能收到任何值,在左侧写赋值语句不会报错,但也没有意义。
那么 send 进入的值,去哪了呢,继续看
yield from 嵌套
<?php
function yield_func20 ()
{$arr = array();
echo 'run to function' . __FUNCTION__ . 'line:' . __LINE__ . PHP_EOL;
$arr[] = yield 2;
$arr[] = yield 'key' => 'value';
$arr[] = yield 7 => 'cc';
$arr[] = yield 5;
echo 'run to function' . __FUNCTION__ . 'line:' . __LINE__ . ', arr re:';
var_export($arr);
echo PHP_EOL;
}
例子:9,10 中,我们实现了,从生成器中取值。同时通过 yield_func20
函数内 $arr
变量 dump 发现,向生成器 send
的值,会通过 yield from
传到内部生成器的 yield
赋值语句.
例子:12,13 中,发现,yield from 是可以多层嵌套的。
yield from 的嵌套作用,是非常重要特性,在协程编码中,熟练使用嵌套能减少函数指针,以及生成器的应用传递。
总结
yield from
是一个强大且不可缺少的语法,如果只有 yield
那么就只是有了生成器,有了 yield from
那就有了一根强大的“针”——穿过一个个 生成器,按照 call stack 把一个个生成器串了起来。调用方法用 call_user_func()
,调用 生成器用 yield from
.
好,这就是 yield from
用法的探究,实战会放到后续文章。
欢迎提问,如果有帮助请关注,收藏,作者有新的发现,干货,也会更新文章。