ホームページ  >  記事  >  バックエンド開発  >  最新PHP新機能シリーズ(4) -- ジェネレーターの作成と使い方

最新PHP新機能シリーズ(4) -- ジェネレーターの作成と使い方

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

1. 概要

ジェネレーターは PHP 5.5 で導入された新機能ですが、実際には非常に便利な機能です。

ジェネレータとイテレータは似ていますが、標準の PHP イテレータとは異なり、PHP ジェネレータは Iterator インターフェイスを実装するクラスを必要としないため、クラスのオーバーヘッドと負担が軽減されます。ジェネレーターは、要件に従って毎回反復する必要がある値を計算して出力します。これは、アプリケーションのパフォーマンスに大きな影響を与えます。標準的な PHP イテレーターがメモリー内で反復操作を頻繁に実行する場合を想像してください。これには、事前の処理が必要です。 - データセットの計算パフォーマンスが低下します。Excel テーブルデータの操作など、特定の方法を使用して大量のデータを計算する場合、パフォーマンスへの影響はさらに大きくなります。現時点では、ジェネレーターを使用すると、貴重なメモリ領域を占有することなく、後続の値を即座に計算して生成できます。

2. ジェネレーターを作成します

ジェネレーターは PHP 関数であるため、ジェネレーターを作成する方法は非常に簡単ですが、関数内で yield キーワードを 1 回以上使用する必要があります。通常の PHP 関数とは異なり、ジェネレーターは値を返すことはなく、値を生成するだけです。これは簡単なジェネレーターの実装です:

function getLaravelAcademy() {    yield 'http://LaravelAcademy.org';    yield 'Laravel学院';    yield 'Laravel Academy';}

とてもシンプルです!このジェネレーター関数が呼び出されると、PHP は Generator クラスに属するオブジェクトを返します。このオブジェクトは、反復ごとに、Generator インスタンスに計算して、反復する次の値を提供するように要求します。ジェネレーターの優れた点は、値が生成されるたびにジェネレーターの内部状態が一時停止され、ジェネレーターから次の値が要求されると内部状態が復元されることです。ジェネレーターの内部状態は、関数定義の終わりに到達するか、空の return ステートメントに遭遇するまで、ストールと再開の間で切り替わります。次のコードを使用して、上記で定義したジェネレーターを呼び出して反復できます:

foreach(getLaravelAcademy() as $yieldedValue) {    echo $yieldedValue, PHP_EOL;}

上記のコードの出力は次のとおりです:

http://LaravelAcademy.orgLaravel学院Laravel Academy

3. ジェネレーターの使用

以下では、値の範囲を生成する単純な関数を実装します。これは、ジェネレーターがどのようにメモリを節約するかを説明します。まずイテレータを介して実装します:

function makeRange($length) {    $dataSet = [];    for ($i=0; $i<$length; $i++) {        $dataSet[] = $i;    }    return $dataSet;}$customRange = makeRange(1000000);foreach ($customRange as $i) {    echo $i . PHP_EOL;}

この時点で、実行中にエラーが報告され、単一の PHP プロセスのメモリ制限を超えていることが通知されます (100 万個の数値に対してメモリ スペースを提供する必要があります):

実装計画を改善し、ジェネレーターを使用してみましょう。 実装は次のとおりです:

function makeRange($length) {    for ($i=0; $i<$length; $i++) {        yield $i;    }}foreach (makeRange(1000000) as $i) {    echo $i . PHP_EOL;}

もう一度実行すると、ジェネレーターは毎回 1 つの整数にメモリを割り当てるだけで済むため、何のストレスもなく結果を出力できます。

また、一般的な使用例は、ジェネレーターを使用してストリーミング リソース (ファイル、オーディオなど) を反復処理することです。サイズが 4 GB の CSV ファイルを反復処理する必要があるとします。仮想プライベート サーバー (VPS) では PHP が使用できるメモリは 1 GB のみであるため、ファイル全体をメモリにロードすることはできません。次のコードは、操作:

function getRows($file) {    $handle = fopen($file, 'rb');    if ($handle == FALSE) {        throw new Exception();    }    while (feof($handle) === FALSE) {        yield fgetcsv($handle);    }    fclose($handle);}foreach ($getRows($file) as $row) {    print_r($row);}

上記の例では、4GB の CSV ファイル全体をメモリに読み取るのではなく、一度に CSV ファイルの 1 行にのみメモリを割り当てます。

4. まとめ

ジェネレーターは、機能の多様性と単純さの間の妥協点です。つまり、ジェネレーターは、データセット内で逆方向、早送り、または検索操作を実行することはできません。ジェネレーターは次の値を計算して生成します。ジェネレーターは、使用するシステム メモリの量が最小限であるため、大規模なデータ セットまたはシーケンスを反復処理する場合に最適です。ジェネレーターは、イテレーターが実行できるのと同じ単純なタスクを、より少ないコードで実行することもできます。

全体として、ジェネレーターは PHP に新しい機能を追加するものではありませんが、ジェネレーターを使用すると、特定のタスクが大幅に簡素化され、データ セットでの巻き戻し、早送り、検索機能の実行など、より多くの機能が必要な場合に使用するメモリが減ります。 Iterator インターフェイスを実装するクラスを自分で記述するか、PHP 標準ライブラリ (SPL) (http://php.net/manual/spl.iterators.php) のネイティブ イテレータを使用するのが最善です。

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