1. ホーム
  2. php

[解決済み】PHPでyieldの意味は何ですか?

2022-03-31 01:11:56

質問

最近、このコードに出会いました。

function xrange($min, $max) 
{
    for ($i = $min; $i <= $max; $i++) {
        yield $i;
    }
}

こんなの見たことない yield というキーワードは初めてです。コードを実行しようとすると

パースエラー: 構文エラー、x行目に予期しないT_VARIABLEがあります。

では、これは何かというと yield キーワードは?これは有効なPHPなのでしょうか?また、有効である場合、どのように使用すればよいのでしょうか?

どのように解決するのですか?

とは yield ?

yield キーワード は、ジェネレータ関数からデータを返します。

ジェネレータ関数の中心はyieldキーワードです。yield文は、関数の実行を停止して戻る代わりに、ジェネレータをループするコードに値を与えてジェネレータ関数の実行を一時停止することを除けば、最も単純な形でreturn文とほぼ同じに見えます。

ジェネレータ関数とは何ですか?

ジェネレータ関数は、事実上、よりコンパクトで効率的な方法で イテレータ . これは、関数 ( xrange を実行します。 を計算し、返します。 間に あなたは ループさせる :

function xrange($min, $max) {
    for ($i = $min; $i <= $max; $i++) {
        yield $i;
    }
}

[…]

foreach (xrange(1, 10) as $key => $value) {
    echo "$key => $value", PHP_EOL;
}

そうすると、次のような出力が得られます。

0 => 1
1 => 2
…
9 => 10

を制御することもできます。 $key の中で foreach を使用することで

yield $someKey => $someValue;

ジェネレーター機能で $someKey に表示させたいものは何でもよい。 $key$someValue の値である。 $val . 質問の例では、それは $i .

通常の機能とは何が違うのですか?

さて、なぜ PHP のネイティブな機能である range 機能 を使えば、その出力を実現することができます。そしてその通りです。出力は同じでしょう。違うのは、そこに至る方法だ。

を使用する場合 range PHP はこれを実行し、数値の配列全体をメモリ上に作成します。 return その 配列全体 から foreach のループがその上を通過し、値を出力します。言い換えれば foreach は、配列そのものを操作することになります。そのため range 関数と foreach は一度だけです。郵便で小包を受け取るようなものだと考えてください。配達員はあなたに荷物を渡して去っていきます。そして、あなたはパッケージ全体の包装を解き、中に入っているものを何でも取り出します。

ジェネレータ関数を使用すると、PHP は関数に踏み込み、終了に達するか、あるいは yield というキーワードがあります。キーワードに出会ったとき yield そして、その時の値を外側のループに返します。そして、ジェネレータ関数に戻り、元の場所に戻ります。あなたの xrange には for ループが実行され $max に到達しました。のようなものだと考えてください。 foreach とジェネレータがピンポンをしているようなものです。

なぜそれが必要なのか?

明らかに、ジェネレータはメモリ制限を回避するために使用することができます。環境によっては range(1, 1000000) はスクリプトを致命的にしてしまいますが、ジェネレータを使えば同じようにうまく動作します。あるいは、Wikipediaによると

ジェネレータは生成された値を必要に応じて計算するので、一度に計算するのが面倒なシーケンスを表現するのに便利である。例えば、無限列やライブデータストリームなどです。

また、ジェネレーターはかなり高速であることが前提となっています。しかし、高速というのは、通常、非常に小さな数字での話であることを覚えておいてください。ですから、すべてのコードをジェネレーターを使用するように変更する前に、ベンチマークを行って、それが意味をなすかどうかを確認してください。

ジェネレータのもう1つのユースケースは、非同期コルーチンです。この場合 yield キーワードは値を返すだけでなく、値を受け取ることもできます。これについての詳細は、以下のリンク先の2つの優れたブログ記事を参照してください。

いつから yield ?

でジェネレータが導入されています。 PHP 5.5 . を使おうとすると yield それ以前のバージョンでは、キーワードに続くコードによってさまざまなパース・エラーが発生します。そのため、そのコードでパースエラーが発生した場合は、PHPを更新してください。

ソースとさらなる読み物