百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>网页制作> PHP yield 协程 生成器用途的理解
分享文章到:

PHP yield 协程 生成器用途的理解

发布时间:09/01 来源:未知 浏览: 关键词:

官网讲解

生成器同意你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创立一个数组, 那会使你的内存到达上限,或者会占据可不雅的处置时间。相反,你可以写一个生成器函数,就像一个一般的自定义函数一样, 和一般函数只返回一次不一样的是, 生成器可以按照需要 yield 屡次,以便生成需要迭代的值。

看了下官网对他讲解:php.net 生成器语法 . 每个字都认识,但好像还是体味到它讲的内在。官网我们主要看两部分内容:

  1. yield 的语法。

  2. 代码例子。

先说语法, yield 的左边是一个赋值语句,右侧可以是值(也可是表达式) 。而yield 会先施行右侧的表达式,并把值$value送到生成器外面。当生成器收到值后,会施行yield左边的语句,赋值给$data.

<?phpfunction func(){
    $data = (yield [$express]);}

语法就这样,估量大家还是有些懵,那就看看官网下面代码例子吧,我看里面例子参差不齐。

留意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,用来检查哪些函数能构成生成器,哪些不克不及。运转结果如下

test result

  1. 函数内必需有 yield 关键词,函数可以是全剧函数,或者类的办法。
  2. 哪怕 yield 必定不会被施行,也会发生生成器。见:yield_func4
  3. 光秃秃 的 yield 关键词就行(不向外送出,不处置外面的输入)。见: yield_func2
  4. 函数内使用 生成器 并不克不及让本人也成为生成器,见:yield_func5
  5. eval函数中直接运转 yield 会报错, 见:yield_func11

是的,函数内有没有foreach,while,for 语句都不是关键,关键是 yield. 生成器的类型推断用 $gen instanceof Generator

生成器的函数

Generator 对象是从 generators返回的.

Generator 对象不克不及通过 new 实例化.

  • Generator::current — 返回当前发生的值
  • Generator::key — 返回当前发生的键
  • Generator::next — 生成器连续施行
  • Generator::rewind — 重置迭代器
  • Generator::send — 向生成器中传入一个值
  • Generator::throw — 向生成器中抛入一个非常
  • Generator::valid — 检查迭代器可否被关闭
  • Generator::__wakeup — 序列化回调
  • Gengerator::getReturn - Get the return value of a generator

摘自 php.net generator

看着以上办法,是不想起了Iterator, 他们确实很像。同时留意,官网zh说话版本的文档没有索引办法getReturn,拜访也是404。文档以en版为准,ch做参照 。

以上就是生成器所有的办法,我们一个个来看。

测试办法代码 /php-yield-test/generatorMothod.php, 这里面临每个办法都有使用举例,运转结果如下。

run result 2

run result 3

好接下来对举例做个一一讲解。

Generator::current

  • 返回当前发生的值
<?phpfunction yield_func(){
    yield 12;
    return 'a';}$gen = yield_func();$re = $gen->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值。
<?phpfunction yield_func(){
    $data = yield 12;
    echo 'get yield data: ' . $data;
    return 'a';}$gen = yield_func();$re = $gen->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::next

  • 跳过中止,并让生成器连续施行
<?phpfunction yield_func(){
    echo 'run to code line: ' . __LINE__ . PHP_EOL;
    yield;
    echo 'run to code line: ' . __LINE__ . PHP_EOL;
    return $result;}$gen = yield_func();$gen->current();echo 'current called' . PHP_EOL;$gen->next();

输出:

run to code line: 4current called
run to code line: 6

例子5,这是一个较为常规的调取,调取current代码运转yield比及会员输入,这是调取next跳过,让代码连续运转。

例子6,直接调取next,相当于调取currentnext。并且通过最后打印$result, 我们发明如何有点像在调取 $gen->send(NULL);

Generator::rewind

  • 重置迭代器
<?phpfunction yield_func(){
    echo 'run to code line: ' . __LINE__ . PHP_EOL;
    $result = yield 12;
    echo 'run to code line: ' . __LINE__ . PHP_EOL;}$gen = yield_func();echo 'call yield_func rewind ' . PHP_EOL;$gen->rewind();

输出:

call yield_func rewind 
run to code line: 4

例子7,8 中,发明调取该办法,会致使隐式调取current

例子9 中,发明在施行过一个yield代码段后,再次调取该办法,会致使报错(哪怕该 生成器已完毕)。

Generator::throw

  • 向生成器中抛入一个非常
<?phpfunction yield_func(){
    try {
        $re = yield 'exception';
    } catch (Exception $e) {
        echo 'catched exception msg: ' .$e->getMessage();
    }}$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::valid

  • 检查迭代器可否被关闭
<?phpfunction yield_func(){
    yield 12;
    return 'a';}$gen = yield_func();$gen->send(1);$check = $gen->valid();echo 'the generator valid ? ' . intval($check);

输出:

the generator valid ? 0

例子12中,发明current被隐式调取。

例子13中,可得,当生成器运转到yield代码段时,用valid函数检查,都会返回true

所以,别问我可否已运转,问就是运转。该办法用来猎取可否关闭状态,不是 可否运转状态!运转到底,运转到return就是 关闭状态。

Generator::key

  • 返回当前发生的键
<?phpfunction yield_func(){
    yield 1 => '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 — 序列化回调
<?phpfunction yield_func(){
    yield 1 => '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

<?phpfunction yield_func(){
    yield 1 => '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 生命周期图

画了两个状态转换图,上面的要详细,繁复一点。下面的精简版,便于快速懂得。

总结

以上就是关于 PHP 生成器的根基内容,但愿你看了后对它有更进一步认识。下一讲,我们手把手一起来做一个任务调度器,实战一下。

有问题欢迎发问,感谢大家!

没人比我更懂

以上就是PHP yield 协程 生成器用途的理解的具体内容,更多请关注百分百源码网其它相关文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有152人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板