前に書いた記事
この記事では、foreach # を使用しないジェネレーターでの PHP yield の使用法について説明したいと思います。 ##、
for、
while のようなループ。
yield を使用して関数をジェネレーターに変換する方法について説明します。
yield
機能に関しては、
PHP5の開発時に議題となり、
PHP5.5バージョンが正式にリリースされました。追加した。
yield の使用に関して、ほとんどの記事が
foreach# で使い果たすために yield
を使用する方法に行き詰まっていることがわかります。 ## データさん、今日はジェネレーターの構文をすべて説明したいと思います。
PHP プログラミングの入門から熟練度まで
公式 Web サイトの説明Generator
foreach ブロックにコードを記述して、メモリ内に配列を作成せずにデータ セットを反復処理できるようにします。これにより、メモリの制限に達したり、かなりの処理時間がかかったりする可能性があります。代わりに、通常のカスタム関数と同じように、ジェネレーター関数を作成できます。一度だけ返す通常の関数とは異なり、ジェネレーターは、必要なだけ何度でも yield
を実行して、値が必要な反復を生成できます。 公式 Web サイトを見て、php.net ジェネレーターの構文を説明しました。私はすべての単語を知っていましたが、それでもその意味を理解しているようでした。公式 Web サイトでは、主に
- 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...
ジェネレーターの生成方法
まず関数を定義し、関数内に yield キーワードを記述し、この関数呼び出しを変数に割り当てます。ジェネレーターが生成されます。 コード /php-yield-test/yieldFunctions.php は、さまざまな構文の組み合わせに従って複数のジェネレーターを定義するジェネレーターです。
テスト コード /php-yield-test/whatIsGenerator.php。どの関数がジェネレーターを形成できるか、どの関数が形成できないかを確認するために使用されます。実行結果は次のとおりです
関数には yield
-
yield
が確実に実行されない場合でも、ジェネレーターは生成されます。参照: yield_func4 - そのままの
yield
キーワードが機能します (送信や外部入力の処理はありません)。参照: yield_func2 - 関数内でジェネレーターを使用しても、それ自体がジェネレーターにはなりません。参照: yield_func5
eval 関数で
yield - を直接実行すると、エラーが報告されます。参照してください。 : yield_func11
-
はい、関数内に foreach、while、または for ステートメントがあるかどうかは関係ありません。重要なのは yield です。
$gen インスタンスオブジェネレーターを使用してください
Generator オブジェクトはジェネレーターから返されます。
##ジェネレーター関数
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, 这里面对每个方法都有使用举例,运行结果如下。
好接下来对举例做个一一讲解。
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
,相当于调用current
,next
。而且通过最后打印$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 イールド コルーチン ジェネレーターの使用法を理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

方法:1、用“str_replace(" ","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\ \;||\xc2\xa0)/","其他字符",$str)”语句。

在php中,可以使用substr()函数来读取字符串后几个字符,只需要将该函数的第二个参数设置为负值,第三个参数省略即可;语法为“substr(字符串,-n)”,表示读取从字符串结尾处向前数第n个字符开始,直到字符串结尾的全部字符。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

Dreamweaver Mac版
ビジュアル Web 開発ツール

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン

SublimeText3 中国語版
中国語版、とても使いやすい

SublimeText3 英語版
推奨: Win バージョン、コードプロンプトをサポート!

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境
