Posted at

phpのgenerator(ジェネレーター)を使ってみた記録

More than 1 year has passed since last update.


初心者のイメージ

初心者が初めて聞いて持ったイメージを忘れないようメモしておきます。

- returnが連打できるのがyield

- phpファイル全体、関数内全体をforeachループで回せる感じ

- 動きとしてはyieldが一つ実行されたら次を待っていてまたジェネレータ関数が呼び出されたら次を実行する感じ


使いどころ(個人的な経験をメモ)


  • 関数でreturnを何回も返したい場合

  • foreachで回しているところを高速化したい

  • forやif、try-catchなど制御構文などの共通部分を抜き出す場合

  • foreachなどの繰り返し処理で回す要素が増え続ける場合


初めてのジェネレータ

色々見ているとなんとなくわかるが理解度を深めるため

とりあえず動くもので最もシンプルと思われるものを動かす。


firstgenerator.php

function first_sinple_generator() {

yield "これを産出";
}

$firstsinplegenerator = first_sinple_generator();
echo $firstsinplegenerator->current();

-------------------------------------------

結果これを産出


まぁこれだとジェネレータの利点が全く見えてこないと思うが

一つ記法として関数なのに自動的にオブジェクトが返ることに注意。

インスタンス化?して使うというところはクラスのようなイメージです。


複数の値を返してみる

複数の値を返すという例でyieldの動きを見てみる。


yields.php

function yields_generator() {

yield "これを産出";
yield "2番目に算出";
yield "3番目に算出";
}

$yields_generator = yields_generator();
echo "currentしてます" . $yields_generator->current();
echo "<br><hr><br>";
echo "currentしてます" . $yields_generator->current();
echo "<br><hr><br>";
echo "1回休み";
echo "nextしてます" . $yields_generator->next();
echo "<br><hr><br>";
echo "2番目のcurrentしてます" . $yields_generator->current();

-------------------------------------------

結果
currentしてますこれを産出
―――――――――――――――――――――――――――――――――――――――――
currentしてますこれを産出
―――――――――――――――――――――――――――――――――――――――――
1回休みnextしてます
―――――――――――――――――――――――――――――――――――――――――
2番目のcurrentしてます2番目に算出


ここで注意したいのはジェネレータクラスのnext関数で

次のyield文に移動するという動き。


使える環境

php5.5以降でgeneratorは使える


メモ


  • foreachよりも早いのがイテレータ。それよりもシンプル記述かつ早いのがジェネレータとのこと


バージョンでの機能追加


  • yield from はphp7以降使用可能

  • ジェネレータ関数内でreturn文が使えるのもphp7以降=


個人的に解りずらかったところ


  • currentメソッドはechoしないと表示されない。


なにも表示されない.php

function first_sinple_generator() {

yield "<br><hr><br>これを産出<br><hr><br>";
}

$firstsinplegenerator = first_sinple_generator();
$firstsinplegenerator->current();

結果:<hr>も含め何も表示されない

echo $firstsinplegenerator->current();
このようにすると表示される



  • そのままジェネレータ関数を実行しても値が返されることはない。
    以下のように書いてみてもFatal error: Uncaught Error: Cannot use object of type Generator as array inのように返ってくる。


エラー.php

/**

* シンプルジェネレータ
* @return Generator
*/

function first_sinple_generator() {
yield "最初の産出";
yield "2番目の産出";
yield "3番目の産出";
}

echo '<br><hr><br>';
$fsinstans = first_sinple_generator();
echo $fsinstans;
echo '<br><hr><br>';
echo $fsinstans;
echo '<br><hr><br>';
echo '一回休んで<br><hr><br>';
echo $fsinstans;
echo '<br><hr><br>';

結果Fatal error: Uncaught Error: Cannot use object of type Generator as array in


yieldを1回ずつ返すには以下のようなやり方がある。


yieldを1回ずつ返す.php


function first_sinple_generator() {

echo "最初のsend";
$yieldvalue = yield;
echo $yieldvalue;

echo "<br><hr>2回目のsend";
$yieldvalue = yield;
echo $yieldvalue;

echo "<br><hr>3回目のsend";
$yieldvalue = yield;
echo $yieldvalue;

}

echo '<br><hr><br>';
$fsinstans = first_sinple_generator();
echo $fsinstans->current();
echo '<br><hr><br>';
echo $fsinstans->send(初めてのsend);
echo '<br><hr><br>';
echo '一回休んで<br><hr><br>';
echo $fsinstans->send("send再び");
echo '<br><hr><br>';
echo $fsinstans->send("sendエピソード0");
echo '<br><hr><br>';


以下のようにyield fromをforeachに渡すことはできない。

foreach ( yield from check_directory_at_s3($information_instans_plugin) as $path_of_hls_file ) {


使ってみた感想

自分の使い方が悪いのですが

あるプログラムをジェネレータでリファクタリングしてみたら

メソッドチェーンのようになってしまい。

結果foreachの数が増えてしまうということがあった。

正しい使い方みたいな情報も見つけられず

ジェネレータの実践的かつ模範的な

ソース情報がありましたら教えてください。