まず、公式の PHP ドキュメントでどのように紹介されているかを見てみましょう。ジェネレーターは、クラスを定義して Iterator インターフェースを実装する場合と比較して、簡単な方法でオブジェクトの反復を実装することができ、パフォーマンスのオーバーヘッドと複雑さが大幅に軽減されます。
この文を読むと、いくつかのキーワードが得られます: オブジェクトの反復、Iterator インターフェイス、パフォーマンスのオーバーヘッド、比較的抽象的、話は安い コードを見せて、ジェネレーターの最も古典的な例から始めましょう。
PHP の range() 関数は、指定された範囲単位を含む配列をメモリ内に作成し、使用時にそれを返します。ただし、渡された制限パラメーターが非常に大きい場合、これは意味します。メモリ内に作成される配列も非常に大きくなるということです。これはメモリがバーストするリズムです。この時点で、ジェネレーターを使用して、より効率的な range 関数を実装できます (次のコードは、公式 PHP ドキュメントの簡略化されたバージョンです):
function xrange($start, $limit, $step = 1) { //校验参数,此处省略 for ($i = $start; $i <= $limit; $i += $step) { //向外产出值 yield $i; } } //xrange此时返回的是一个生成器对象 $gen = xrange(1, 9); //对生成器进行迭代 foreach ($gen as $number) { echo "$number "; }
ここでは、xrange 関数と range 関数は同じ効果があり、どちらも Iterable 変数を生成します。ただし、違いは、range 関数は ORM でよく言われる「プリロード」に少し似ているのに対し、xrange は「遅延ロード」であり、反復がそのポイントに達するまで待機して対応する値を生成するだけであるため、xrange はそれを行う必要がないことです。大きなメモリ ブロックを割り当てる 変数を保存すると、メモリが大幅に節約され、効率が向上します。
次に、ジェネレーターと通常の関数の類似点と相違点をまとめてみましょう:
ジェネレーターには、yield キーワード (結果の生成に使用) が含まれている必要があり、通常の関数では、結果のみが外部に返されます。 Return を使用でき、関数が実行されます。
ジェネレーターは return を使用して値を返すことはできません。これを行うとコンパイル エラーが発生します。 PHP の致命的なエラー: ジェネレーターは "return" を使用して値を返すことができません (注:これは PHP7 では使用できません。エラーが発生しますが、ジェネレーターは終了して実行を継続します。つまり、 valid() メソッドを呼び出すと false が返されます。ただし、return null は PHP5 では有効な構文であり、ジェネレーターは終了します。実行を継続します)
Generator オブジェクトはジェネレーターから返されます。上記のコードでは、$gen がジェネレーター オブジェクトです。ジェネレーター オブジェクトは他のクラスのオブジェクトとは異なり、new キーワードを使用して作成することはできず、ジェネレーター関数からのみ取得できることに注意してください。まず、Generator クラスの概要を見てその構成を見てみましょう:
Generator implements Iterator { /** * 返回当前产生的值(yield后面表达式的值) */ public mixed current ( void ) /** * yield的键(yield 'key'=>'val';) */ public mixed key ( void ) /** * 从上一个yield之后继续执行,直到下一个yield */ public void next ( void ) /** * 重置迭代器(对于生成器并没什么卵用) */ public void rewind ( void ) /** * 向生成器中传入一个值,并从上一个yield之后继续执行 */ public mixed send ( mixed $value ) /** * 向生成器中抛出一个异常,并从上一个yield之后继续执行 */ public void throw ( Exception $exception ) /** * 检查迭代器是否被关闭(false表示已关闭) */ public bool valid ( void ) /** * 序列化回调,但是生成器不能被序列化,因此会抛出一个异常 */ public void __wakeup ( void ) }
上記のクラスの概要から、Generator クラスが Iterator インターフェイスを実装しているため、イテレータの特性があることがわかります。さらに、send()、throw()、および __wekeup() メソッドが追加されます。関連するメソッドの説明はコメント化されているため、ここでは繰り返しません。
色々書いて文章が下手だったので、雰囲気を掴むために絵を描いてみようかな(絵も綺麗じゃないので、このまま我慢しましょう、2333)
次に見てみましょう yield キーワードは、最も単純な形では通常の関数の戻り値と似ていますが、通常の戻り値は値を返して関数の実行を終了するのに対し、yield キーワードは値を返すという点が異なります。このジェネレーターを呼び出すためにループするコードに値を指定し、ジェネレーター関数の実行を一時停止するだけです。
これは典型的な yield 式です: $data = yield $key => $value; この式には 2 つの部分が含まれています:
注: PHP5 では括弧が必要です $data = (yiel<br/>d $key => $value);,そうしないとコンパイルエラーが発生します。PHP7 はこれを気にする必要はありません
まず、これは、yield の後の式であり、単一の値またはキーと値のペア、および配列内の要素にすることができます。式の一部は上位層の呼び出しに返されます。つまり、上位層は現在のメソッドを通じて値を受け取るか、send メソッドの戻り値を実行できます
他の部分は、yield キーワード自体です。個人的には、受信者は send メソッドによって渡された値を受け取ります。この値は、yield 式全体の現在の値であり、左側の変数で受け取ることができます。
これは少し抽象的かもしれませんが、上の図を見てみましょう:
PHP7 は、他のジェネレーター、Traversable オブジェクトから構文を開始できるようにする yield from キーワードを追加しました。 、または配列 値を生成するには、ジェネレータ関数からのyieldを使用します。 yield from のさまざまな特性は、データを生成する yield と同じですが、その後の式が異なります。例を見てみましょう (PHP 公式ドキュメントから抜粋):
function count_to_ten() { yield 1; yield 2; yield from [3, 4]; //生成数组 yield from new ArrayIterator([5, 6]); //生成可遍历对象 yield from seven_eight(); //生成生成器对象 yield 9; yield 10; } function seven_eight() { yield 7; yield from eight(); } function eight() { yield 8; } foreach (count_to_ten() as $num) { echo "$num "; } //输出:1 2 3 4 5 6 7 8 9 10
yield from以方便我们编写比较清晰生成器嵌套,这点可以类比于函数中的嵌套调用,当函数A中调用另一个函数B,此时会等B执行完成并返回,方才继续执行。在没有yield from的时候,实现生成器嵌套需要自己实现栈并进行压栈和弹出操作以达到相同效果,那是多么痛苦的操作。
相关推荐:
以上がPHPジェネレーターの詳しい紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。