/ #php #プログラミング 

PHPでジェネレーター構文【yield】を使いたい時のサンプルコード集

PHPのジェネレーター構文yieldを使って処理を書きたい人へ
シンプルに理解できるサンプルコードとその解説を書きます。
業務でググってここに来た方、PHPを勉強している方、自由にコピペしてお使いください。

自分は現在フリーランスエンジニアとしてゲームプログラミングの業務をしています。
その際のランキング集計処理を作る時にジェネレーター構文を使いました。
理由はランキングの件数が10万レコード超えを想定していて、メモリ削減が必須だったからです。

その時に調査し参考にしたコード達を共有したいと思います。

目次

  1. ジェネレーター構文 yieldって何?
  2. 基本の使い方
  3. 応用の使い方
  4. ジェネレーター構文が必要になるシーン

1. ジェネレーター構文 yieldって何?

ジェネレーター構文を使うと、メモリを抑えてスッキリと繰り返し処理を書けます。

【登場人物】

  • ジェネレーター関数さん: yieldで値を返す関数。foreachで呼ばれた時に順番に値を返せます。
  • yieldさん: returnの代わりに使うと、順番に値を返すことができます。
  • foreach(ジェネレーター関数 as $item)さん:ジェネレーター関数を何回も呼ぶ人

以下に表示するコードを実行したり、中身を変更したりして試してください。

2. 基本の使い方

<?php
    // yieldを使うと順番に値を返す事ができるジェネレーター関数になる 
    function yieldSample()
    {
        yield 'hoge'; //1回目に返す値
        yield 'foo'; //2回目に返す値
        yield 'bar'; //3回目に返す値
    }
 
    // ジェネレーター関数は順番にyieldの値を返して$itemに入れます
    foreach(yieldSample() as $item) {
        echo "$item\n";
    }
    
    // 配列で同じ事を書くと
    foreach(['aaa','bbb','ccc'] as $item) {
        echo "$item\n";
    }

ここにコピペで貼っつけて実行して試すことができます。
yieldを増やしたり、hogeを変えたりして実験してみてください。
もしソースが崩れてたらコピぺして戻してみてください。

  1. yieldを使うと順番に値を返す事ができるジェネレーター関数になる
  2. yieldで値を返すと、そこで処理が一時停止して呼び出し元の処理が走る
  3. foreachで呼ばれたieldSample()は順番にyieldの値を返して$itemに入れます

つまり、順番にhoge,foo,barと返されてechoで順番に表示されます。

実際に業務で使う場合は下記の応用の使い方の様に
forやforeachでyieldを返すとリーダブルなコードになります。

3.応用の使い方

<?php
    // ユーザを順番に作るジェネレーター関数
    function yieldMakeUser($limit)
    {
        for($i = 1; $i <= $limit; $i++) {
            $userId = 'User' . $i;
            // 業務ではここに複雑な処理を記述する事になるでしょう
            yield $userId;
        }
    }
 
    // ユーザを5人作る
    foreach(yieldMakeUser(5) as $userId) {
        print($userId."\n");
    }

実行環境はこちら。実行ボタンを押して試してください。

ユーザを順番に作るジェネレーター関数の中でyieldで順番にuserIdを作って返しています。
ポイントは5回繰り返しているのに、ジェネレーター関数内では1回分の処理メモリしか使用しない点です。
forの中でyieldを使い値を返す事で、一回ずつ処理呼び出し元に値を返しています。

業務で使用する場合はforの中に初期処理や複雑な処理を記述する事になるでしょう。

4. ジェネレーター構文が必要になるシーン

ジェネレーター関数にする事で配列を返す関数よりもメモリ使用量を抑える事ができます。
例えばランキング処理で10万人のデータを巨大な配列やコレクションに入れて、
繰り返し処理を実行するのはメモリが足りなくて、現実的ではありません。
1000件ずつの処理を100回繰り返す処理を作る事になると思います。

そんな時にジェネレーター構文を使うと、メモリ使用量を1000件分に抑える事ができます。

まとめ

以上、簡単でしたが、ジェネレーター構文を使いたい時のサンプルコードでした。

実際業務で使う場合は複雑な処理を繰り返し使うと思いますが、
その複雑な処理を関数にまとめてしまい、その関数をジェネレーター関数の中で呼べば、
簡単に負荷分散される繰り返し処理が作れると思います。
ぜひご参考にしていただければと思います。

このブログではフリーランス情報やプログラミング情報の発信を
続けていこうと思うのでぜひ応援お願いします。
また、Twitterでも日々の為になる技術情報やフリーランスについての
有益な情報をつぶやくので、いいなと思った方はTwitterのフォローをお願いします。

ブログの著者:IT業界10年以上のベテランフリーランスエンジニア。
会社員時代に比べ年収2.5倍にUP。
AWSとGCPの両方でゲーム系インフラの構築,運用と
C#とPHPでのサーバープログラミングの二刀流で絶賛稼働中。
有益なIT情報を発信出来きるように日々IT情報収集が日課です。
ブログではフリーランスやIT情報を毎日更新中です。

自分のスキルレベルと経歴をまとめたページを作りました。
お仕事のご依頼の際には参考にしていただければと思います。
クラウドランス 望月 のポートフォリオサイト
またブログに関する感想やご意見、応援などがありましたら、
こちらから自分宛てにTweetして頂ければと思います。