PHP yield 协程 生成器用法的了解-php教程

资源魔 44 0

写正在后面

这篇文章,要以及各人讨论的是 PHP yield 正在 天生器用法,没有带 foreachfor, while 轮回的那种。就探讨 yield 将一个函数变为为天生器的用法。

对于yield 特点,是正在开发 PHP5 时被提上日程,PHP5.5 版本正式退出。

对于yield的应用,我看到年夜局部文章都停留正在,应用yield若何正在foreach中穿出数据,明天想给各人讲讲 天生器 一切语法。

相干学习保举:PHP编程从入门到通晓

官网解说

天生器容许你正在 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 可以猎取到天生器最初的前往值。

例子1九、20 可患上,当天生器不执行到return语句,或许不执行到最初时,挪用getReturn是会招致报错。

综上所述

到这里,咱们就发现rewind,next 以及 __wakeup 这两个函数觉得没啥叼用呢,为啥还存正在呢,由于Generator承继Iterator,天然就有了rewind, next办法,PHP 尽管支持办法笼罩,但子类的拜访润饰符 不克不及缩紧,以是Generator只能重写这两个办法。 __wakeup 承继自 stdClass

状态转换

看图:

PHP yield 生命周期图

画了两个状态转换图,下面的要粗疏,繁复一点。上面的精简版,便于疾速了解。

总结

以上就是对于 PHP 天生器的根底内容,心愿你看了后对它有更进一步意识。下一讲,咱们手把手一同来做一个义务调剂器,实战一下。

有成绩欢送发问,谢谢各人!

没人比我更懂

以上就是PHP yield 协程 天生器用法的理解的具体内容,更多请存眷资源魔其它相干文章!

标签: php php开发教程 php开发资料 php开发自学 yield 协程 生成器

抱歉,评论功能暂时关闭!