ホームページ >バックエンド開発 >PHPチュートリアル >Php5.5ジェネレータの新機能を詳しく解説

Php5.5ジェネレータの新機能を詳しく解説

WBOY
WBOYオリジナル
2016-06-23 13:33:211000ブラウズ

**PHP5.5.0** バージョンでは、単純な反復子を作成するための反復子インターフェイス *(Iterator)* の実装の複雑さを簡素化するために、ジェネレーター *(Generators)* 機能が追加されました。

ジェネレーターを使用すると、反復するオブジェクトを事前にメモリ内に構築する必要がなく、foreach を使用して一連のデータを反復することが簡単にできるため、メモリのオーバーヘッドが大幅に削減されます。

ジェネレーター関数が呼び出されると、オブジェクトを反復処理するときに、PHP は必要に応じてジェネレーター関数を呼び出し、ジェネレーターで新しいキーを使用します。yield という単語が新しい値を生成すると、保存されます。イテレータの内部状態。イテレータに生成する新しい値がない場合、ジェネレータ関数は直接終了でき、外部関数は実行を継続します。

ジェネレーター関数では、return ステートメントを使用して値を返すことはできません。値を返すために return を使用すると、コンパイラ エラーが生成されることに注意してください。ただし、イテレータが終了する空の return を使用することは問題ありません。

ジェネレーター関数は通常の関数と同じですが、唯一の違いは、関数内で yield キーワードが使用されることです。 yield ステートメントはジェネレーター関数の核心であると言えます。yield ステートメントは return ステートメントと同じですが、return ステートメントを使用して return を実行した後に関数が終了するという点が異なります。関数は単に一時停止され、外部関数に転送され、次回ジェネレーター関数が呼び出されたときに、ジェネレーター関数内のコードの実行が続行されます。

簡単な例 - range 関数のジェネレーター バージョン

簡単な例では、foreach 反復関数 range の戻り値を使用します。 range(0, 1000000) を呼び出すと、100M を超えるメモリが消費されます。ジェネレーターを使用する場合、消費するメモリは 1KB 未満にとどまります。

<?phpfunction xrange($start, $end) {    if ($start > $end) {        throw new RuntimeException("起始值不能大于截止值");    }    for ($i = $start; $i <= $end; $i += 1) {        // 使用yield关键字,每次到这里函数都会返回$i的值,并且控制权交给外部函数继续执行        yield $i;    }}foreach (xrange(1, 9) as $number) {    echo "$number ";}

上の例の出力は次のとおりです:

上の例では、関数内で Yield という名前の関数を作成して戻り値を継続的に生成し、xrange(1, 9) を呼び出すと、ジェネレーターオブジェクトを作成します。 xrange オブジェクトを出力するように foreach 行を変更すると、

...$xrange_res = xrange(1, 9);var_dump($xrange_res);foreach( $xrange_res as $number){...

Output

xrange(1, 9) が実行されると、実際に Generator オブジェクトが返されることがわかります。

Generator オブジェクトの send メソッドを使用します

上記の例では、yield ステートメントを使用すると、別のステートメント行として実行されます。つまり、yield ステートメントは結果を外部に生成します。反復プロセスから結果を取得する方法 ジェネレーター関数の外で値を取得する場合はどうすればよいでしょうか?

ジェネレーター関数を呼び出した後、Generator オブジェクトが返されるため、send メソッドを呼び出した後、オブジェクトの send メソッドを呼び出して外部からジェネレーター関数に値を渡すことができるため、常に方法があります。 send 関数に送信された値を収集します。

<?phpfunction gen() {    $ret = (yield 'yield1');    var_dump("-->" . $ret);    $ret = (yield 'yield2');    var_dump("-->" . $ret);}$gen = gen();var_dump($gen->current());var_dump($gen->send('ret1'));var_dump($gen->send('ret2'));

出力:

ここでは、まず gen という名前のジェネレーター オブジェクトを作成し、次に $gen->current() メソッドの戻り値を出力します。これはイテレーターの最初の反復中に生成されます。なので、yield1 が出力されます。

次に $gen->send('ret') メソッドを呼び出します。このとき、ジェネレーターの最初の yield ステートメントはメソッドによって渡された値 ret1 を返すため、$ret の値は ret1 として出力されます。

その後、ジェネレーターは 3 番目のステートメント $ret = (yield 'yield2') を内部で実行するため、2 番目の外部 var_dump は yield2 を出力します。 $gen->send('ret2') への最後の呼び出しは最初と似ていますが、今回はジェネレーターが内部で yield を呼び出した後、yield がないため、NULL が返されます。

ここでの $ret = (yield 'yield2') ステートメントでは、yield 'yield2' ステートメントが括弧内に含まれていることに注意してください。これは、式コンテキストで yield を使用する場合、yield を括弧内に置く必要があります。それ以外の場合は、エラーが報告されます。

連想配列を返す

前の例では、常に 1 つの値を返すために yield キーワードを使用しました。毎回、マネージド配列を走査した場合と同じ結果を返します。

yield key => val

出力:

参照の使用

ジェネレーターの内部データの値をジェネレーターの外部で直接変更できるように、ジェネレーターに参照の形式でデータを返させることもできます。

<?phpfunction gen2() {    $array = [        'username' => 'mylxsw',        'site'     => 'http://aicode.cc'    ];    foreach ($array as $key => $val) {        yield $key => $val;    }}foreach(gen2() as $key => $val) {    var_dump($key . '   :   ' . $val);}

上記の例では、&$number がジェネレーター関数の定義と走査で使用されていることに注意してください。

最後に、ジェネレーターはカスタム反復子オブジェクトとまったく同じではありません。ジェネレーターが反復を開始すると、巻き戻すことはできず、反復が完了するまで前方に反復することしかできません。ジェネレーター オブジェクトを複数回反復する場合は、ジェネレーター関数を複数回呼び出して新しいジェネレーター オブジェクトを作成するか、 clone キーワードを使用します。

参考:

コルーチン (PHP で!) ジェネレーターを使用した協調マルチタスク

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。