SlideShare a Scribd company logo
1 of 63
Download to read offline
PHPカンファレンス2012


PHP5.5新機能                かもしれない




Generator
初心者入門
makoto kuwata <kwa@kuwata-lab.com>
http://www.kuwata-lab.com/
2012-09-15 (Sat)




                    copyright(c) 2012 kuwata-lab.com all rights reserved.
本発表について
【目的】 • PHP5.5の新機能かもしれない「ジェネレータ」を、
       「なんだか凄そうだ」と思ってもらう。


【内容】 • ジェネレータって何?
      • どううれしいの?
      • どんなことに使えるの?


【注意】 • 内容は2012-09-15時点での情報に基づく。
       今後、仕様変更があり得るので注意。


          copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータって何?
What is Generator?




                copyright(c) 2012 kuwata-lab.com all rights reserved.
まとめ

◆ ジェネレータ                                     セーブ機能


◆ ジェネレータ関数                                   ゲームシナリオ


◆ ジェネレータオブジェクト                                            冒険の書
                                                        (セーブデータ)

◆ yield文                                     宿屋(セーブポイント)


           copyright(c) 2012 kuwata-lab.com all rights reserved.
通常の関数

	 1:	 function	 func()	 {
	 2:	 	 	 	 $i	 =	 0;
                         1, 2, 3回目 (0が返される)
	 3:	 	 	 	 return	 $i;
	 4:	 	 	 	 $i++;
	 5:	 	 	 	 return	 $i;
	 6:	 	 	 	 $i++;
	 7:	 	 	 	 return	 $i;
	 8:	 }
                     毎回先頭から実行され、また
                   return文より後ろは実行されない


            copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータ (Generator) 関数

	 1:	 function	 gfunc()	 {
	 2:	 	 	 	 $i	 =	 0;
                        1回目 (0が返される)
	 3:	 	 	 	 yield	 $i;
	 4:	 	 	 	 $i++;
	 5:	 	 	 	 yield	 $i;  2回目 (1が返される)
	 6:	 	 	 	 $i++;
	 7:	 	 	 	 yield	 $i;  3回目 (2が返される)
	 8:	 }
           前回の終了位置から再開



           copyright(c) 2012 kuwata-lab.com all rights reserved.
使い方
         ジェネレータオブジェクトを生成
       (通常の関数と使い方が違うことに注意!)

	 1:	 $g	 =	 gfunc();
	 2:	 foreach	 ($g	 as	 $x)	 {
	 3:	 	 	 	 var_dump($x);
	 4:	 }
                         foreach文とともに使用
                       (イテレータとして振る舞う)
実行例
int(0)
int(1)
int(2)

             copyright(c) 2012 kuwata-lab.com all rights reserved.
実行順序:ループ1回目

メインプログラム                                    ジェネレータ関数

1
  $g	 =	 gfunc();                            function	 gfunc(){
2
  foreach($g	 as	 $x){                       	 	 $i	 =	 0;
                                               3
  	 	 var_dump($x);                          	 	 yield	 $i;
                                               4
    5
  }                                          	 	 $i++;
  echo	 "donen";                            	 	 yield	 $i;
                                             	 	 $i++;
                                             	 	 return	 $i;
                                             }

              copyright(c) 2012 kuwata-lab.com all rights reserved.
実行順序:ループ2回目

メインプログラム                                    ジェネレータ関数
  $g	 =	 gfunc();                            function	 gfunc(){
6
  foreach($g	 as	 $x){                       	 	 $i	 =	 0;
  	 	 var_dump($x);                          	 	 yield	 $i;
    9
  }                                          	 	 $i++;
                                               7

  echo	 "donen";                            	 	 yield	 $i;
                                               8
                                             	 	 $i++;
                                             	 	 return	 $i;
                                             }

              copyright(c) 2012 kuwata-lab.com all rights reserved.
実行順序:ループ3回目…は、ない

 メインプログラム                                   ジェネレータ関数
  $g	 =	 gfunc();                            function	 gfunc(){
10foreach($g	 as	 $x){                       	 	 $i	 =	 0;
  	 	 var_dump($x);                          	 	 yield	 $i;
  }                                          	 	 $i++;
                                             	 	 yield	 $i;
13echo	 "donen";
                                             	 	 $i++;
                                             11
                                             	 	 return	 $i;
                                             12
・ループのたびにyield文まで実行
・yield文の引数がループ変数に
                                             }

              copyright(c) 2012 kuwata-lab.com all rights reserved.
サンプル:2つの値を交互に出力

	 1:	 function	 toggle($odd,	 $even)	 {
	 2:	 	 	 	 while	 (TRUE)	 {
	 3:	 	 	 	 	 	 	 yield	 $odd;
	 4:	 	 	 	 	 	 	 yield	 $even;
	 5:	 	 	 	 }
	 6:	 }
	 7:	 
	 8:	 //	 "red"	 と	 "blue"	 を交互に出力
	 9:	 foreach	 (toggle("red",	 "blue")	 as	 $c){
10:	 	 	 	 echo	 $c,	 "n";	 	 //	 無限に出力
11:	 }


              copyright(c) 2012 kuwata-lab.com all rights reserved.
サンプル:フィボナッチ数列 (0, 1, 1, 2, 3, 5, 8, 13,...)

	 1:	 function	 fib()	 {
	 2:	 	 	 	 $x	 =	 0;	 $y	 =	 1; コツ:ループの終了条件を
	 3:	 	 	 	 while	 (TRUE)	 {         指定しない (無限ループ)
	 4:	 	 	 	 	 	 	 yield	 $x;
	 5:	 	 	 	 	 	 	 list($x,	 $y)	 =	 [$y,	 $x+$y];
	 6:	 	 	 	 }
	 7:	 }
	 8:
	 9:	 //	 100未満のフィボナッチ数列を出力
10:	 foreach	 (fib()	 as	 $x)	 {
11:	 	 	 	 if	 ($x	 >=	 100)	 break;
12:	 	 	 	 echo	 $x,	 "n";             コツ:終了条件は呼
13:	 }                                  び出す側で指定する

              copyright(c) 2012 kuwata-lab.com all rights reserved.
まとめ

◆ ジェネレータ                                     セーブ機能


◆ ジェネレータ関数                                   ゲームシナリオ


◆ ジェネレータオブジェクト                                            冒険の書
                                                        (セーブデータ)

◆ yield文                                     宿屋(セーブポイント)


           copyright(c) 2012 kuwata-lab.com all rights reserved.
どううれしいの?
Why Generator is so useful?




                copyright(c) 2012 kuwata-lab.com all rights reserved.
Before: ファイルを1行ずつ処理する

	 1:	 	 	 	 //	 行番号つきで表示
	 2:	 	 	 	 $f	 =	 fopen($filename,	 'r');
	 3:	 	 	 	 if	 ($f	 ===	 FALSE)	 throw	 ....;
	 4:	 	 	 	 $line	 =	 fgets($f);
	 5:	 	 	 	 while	 ($line	 !==	 FALSE)	 {
	 6:	 	 	 	 	 	 	 ++$i;
	 7:	 	 	 	 	 	 	 echo	 $i,	 ":	 ",	 $line;
	 8:	 	 	 	 	 	 	 $line	 =	 fgets($f);
	 9:	 	 	 	 }
10:	 	 	 	 fclose($f);
11:	 
               copyright(c) 2012 kuwata-lab.com all rights reserved.
Before: ファイルを1行ずつ処理する

	 1:	 	 	 	 //	 パターンで絞り込む
	 2:	 	 	 	 $f	 =	 fopen($filename,	 'r');
	 3:	 	 	 	 if	 ($f	 ===	 FALSE)	 throw	 ....;
	 4:	 	 	 	 $line	 =	 fgets($f);
	 5:	 	 	 	 while	 ($line	 !==	 FALSE)	 {
	 6:	 	 	 	 	 	 	 if	 (preg_match('/@/',	 $line))
	 7:	 	 	 	 	 	 	 	 	 	 echo	 $line;
	 8:	 	 	 	 	 	 	 $line	 =	 fgets($f);
	 9:	 	 	 	 }
10:	 	 	 	 fclose($f);
11:	 
              copyright(c) 2012 kuwata-lab.com all rights reserved.
Before: ファイルを1行ずつ処理する

	 1:	 	 	 	 //	 タブ文字でフィールドに分解
	 2:	 	 	 	 $f	 =	 fopen($filename,	 'r');
	 3:	 	 	 	 if	 ($f	 ===	 FALSE)	 throw	 ....;
	 4:	 	 	 	 $line	 =	 fgets($f);
	 5:	 	 	 	 while	 ($line	 !==	 FALSE)	 {
	 6:	 	 	 	 	 	 	 $arr	 =	 explode("t",	 $line);
	 7:	 	 	 	 	 	 	 echo	 $arr[1],	 "n";
	 8:	 	 	 	 	 	 	 $line	 =	 fgets($f);
	 9:	 	 	 	 }                    汎用性の高いコードの中に
10:	 	 	 	 fclose($f);           汎用性の低いコードが混在
11:	 
              copyright(c) 2012 kuwata-lab.com all rights reserved.
After: ジェネレータ関数
                                            汎用性の高い箇所を関数に抽出

	 1: function	 each_line($filename)	 {
	 2:	 	 	 	 $f	 =	 fopen($filename,	 'r');
	 3:	 	 	 	 if	 ($f	 ===	 FALSE)	 throw	 ....;
	 4:	 	 	 	 $line	 =	 fgets($f);
	 5:	 	 	 	 while	 ($line	 !==	 FALSE)	 {
	 6:	 	 	 	 	 	 	 $arr	 =	 explode("t",	 $line);
                  yield	 $line;
	 7:	 	 	 	 	 	 	 echo	 $arr[1];
                        汎用性の低い箇所を yield 文に
	 8:	 	 	 	 	 	 	 $line	 =	 fgets($f);
	 9:	 	 	 	 }
10:	 	 	 	 fclose($f);
11:	 }
               copyright(c) 2012 kuwata-lab.com all rights reserved.
After: メインプログラム

	 1:	 //	 ジェネレータオブジェクトを生成
	 2:	 $g	 =	 each_line($filename);
	 3:	 //	 メインループ
	 4:	 foreach	 ($g	 as	 $line)	 {
	 5:	 	 	 	 //	 汎用性の低い処理
	 6:	 	 	 	 $arr	 =	 explode("t",	 $line);
	 7:	 	 	 	 echo	 $arr[1],	 "n";
	 8:	 }




              copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータの利点

◆ ループ処理から、汎用性の高い箇所だけを切り
  出せる(再利用性の向上)
◆


◆


◆



      copyright(c) 2012 kuwata-lab.com all rights reserved.
もっとジェネレータ関数
          ジェネレータオブジェクトを受け取り、新し
          い別のジェネレータオブジェクトを生成する

	 1:	 	 	 	 //	 ジェネレータオブジェクトを作成            受け取る
        function	 each_fields($g)	 {
	 2:	 	 	 	 $g	 =	 each_line($filename);
	 3:	 	 	 	 //	 ループ                   配列やイテレータでも可
	 4:	 	 	 	 foreach	 ($g	 as	 $line)	 {
	 5:	 	 	 	 	 	 	 $arr	 =	 explode("t",	 $line);
	 6:	 	 	 	 	 	 	 echo	 $arr[1];
                  yield	 $arr;
	 7:	 	 	 	 }
	 8: }



             copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータを「重ねる」

	 1:	 //	 ジェネレータオブジェクトを生成
	 2:	 $g	 =	 each_line($filename);
	 3: $g	 =	 each_fields($g);         ジェネレータから
	 4:	 //	 メインループ                     別のジェネレータ
	 5:	 foreach	 ($g	 as	 $line)	 { を生成
                          $arr
	 6:	 	 	 	 $arr	 =	 explode("n",	 $line);  
                                            	 
	 7:	 	 	 	 echo	 $arr[1],	 "n";
	 8:	 }



             copyright(c) 2012 kuwata-lab.com all rights reserved.
1つの大きなループ vs. 複数の小さなループ

ジェネレータ使用前                                                  ジェネレータ使用後
$f	 =	 fopen($filename,	 'r');                              while	 ($line	 !==	 FALSE)	 {
$line	 =	 fgets($f);                                        	 	 yield	 $line;
while	 ($line	 !==	 FALSE)	 {                               }
	 	 $arr	 =	 explode("n",$line);	 
	 	 echo	 $arr[1];                                          foreach	 ($g	 as	 $line)	 {
	 	 $line	 =	 fgets($f);                                    	 	 yield	 $arr;
}                                                           }
fclose($f);
                                                            $g	 =	 each_line($filename);
                                                            $g	 =	 each_fields($g);
                                                            foreach	 ($g	 as	 $arr)	 {
                                                            	 	 echo	 $arr[1],	 "n";
                                                            }



                     copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータの利点

◆ ループ処理から、汎用性の高い箇所だけを切り
  出せる(再利用性の向上)
◆ ひとつの大きなループを、複数の小さなループ
  に分解できる(ループの簡素化とPipeline化)
◆


◆



        copyright(c) 2012 kuwata-lab.com all rights reserved.
従来方法との比較:配列にすべて格納する

	 1:	 function	 each_line($filename)	 {
	 2:	 	 	 	 $f	 =	 fopen($filename,	 'r');
	 3:	 	 	 	 $lines	 =	 array(); メモリを大量に消費
	 4:	 	 	 	 $line	 =	 fgets($f);(巨大データだと落ちる)
	 5:	 	 	 	 while	 ($line	 !==	 FALSE)	 {
	 6:	 	 	 	 	 	 	 $lines[]	 =	 $line;
	 7:	 	 	 	 	 	 	 $line	 =	 fgets($f);
	 8:	 	 	 	 }
	 9:	 	 	 	 fclose($f);          すべてを読み込まないと
10:	 	 	 	 return	 $lines;        結果が返ってこない
11:	 }

            copyright(c) 2012 kuwata-lab.com all rights reserved.
従来方法との比較:ジェネレータ

	 1:	 function	 each_line($filename)	 {
	 2:	 	 	 	 $f	 =	 fopen($filename,	 'r');
	 3:	 	 	 	 
                                 1度に1行しか読み込まない
	 4:	 	 	 	 $line	 =	 fgets($f); (巨大なデータでも落ちない)
	 5:	 	 	 	 while	 ($line	 !==	 FALSE)	 {
	 6:	 	 	 	 	 	 	 yield	 $line;
	 7:	 	 	 	 	 	 	 $line	 =	 fgets($f);
	 8:	 	 	 	 }                 読み込んだはしから値を返す
	 9:	 	 	 	 fclose($f); (ストリーム処理に最適)
10
11:	 }

             copyright(c) 2012 kuwata-lab.com all rights reserved.
リダイレクト v.s. パイプライン

すべてを配列に格納する                                  ≒「リダイレクト」
・巨大な中間ファイルが必要
・最後まで処理しないと何も出力されない


bash% command1 < input > tmp1
bash% command2 < tmp1 > tmp2
bash% command3 < tmp2



          copyright(c) 2012 kuwata-lab.com all rights reserved.
リダイレクト v.s. パイプライン

ジェネレータを連結する                                  ≒ 「パイプ」
・巨大な中間ファイルがいらない
・読み込んだはしから出力される


bash% cat input | command1 
                | command2 
                | command3



          copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータの利点

◆ ループ処理から、汎用性の高い箇所だけを切り
  出せる(再利用性の向上)
◆ ひとつの大きなループを、複数の小さなループ
  に分解できる(ループの簡素化とPipeline化)
◆ メモリ消費量が少ない
  (巨大なデータを扱ってもプロセスが落ちない)
◆ データを読んだはしから処理できる
  (ストリームデータも処理可能)

        copyright(c) 2012 kuwata-lab.com all rights reserved.
どんな使い道があるの?
Advanced Generator




               copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータとインタラクション

$g->send() … 次のyield文まで実行する

             メインプログラム                                               ジェネレータ関数
                                                                    からメインプログ
                                                                    ラムに値を返す
   foreach(){}                                               yield	 $value
 $g->send($arg)

メインプログラム
                 ジェネレータ関数
からジェネレータ
関数に値を渡せる



            copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータとインタラクション

双方向への値の受け渡しが可能に
メインプログラム

    $value	 =	 $g->send("arg");

                                                       send()の引数が
                                                       yield文の値に

                                                      yield文の引数が
                                                      send()の戻り値に
ジェネレータ関数
     $arg	 =	 (yield	 "value");

           copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータとインタラクション

メインプログラム                                     ジェネレータ関数

1$g	 =	 gfunc();                              function	 gfunc(){
$ret	 =	 $g->send(1);                         	 	 $arg	 =	 yield;
       2                                        3
$ret	 =	 $g->send(2);                         	 	 while	 (条件式)	 {
                                                 4
$ret	 =	 $g->send(3);                         	 	 	 	 $ret	 =	 ...;
                                                    5
                                              	 	 	 	 $arg	 =
                                              	 	 	 	 	 	 (yield	 $ret);
                                                        6
                                              	 	 	 	 var_dump($arg);
                                              	 	 }
                                              }

               copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータとインタラクション

メインプログラム                                   ジェネレータ関数
$g	 =	 gfunc();                             function	 gfunc(){
$ret	 =	 $g->send(1);                       	 	 $arg	 =	 yield;
$ret	 =	 $g->send(2);                       	 	 while	 (条件式)	 {
                                              9
        7
$ret	 =	 $g->send(3);                       	 	 	 	 $ret	 =	 ...;
                                                 10
                                            	 	 	 	 $arg	 =
                                            	 	 	 	 	 	 (yield	 $ret);
                                                     11
                                            	 	 	 	 var_dump($arg);
                                                  8
                                            	 	 }
                                            }

             copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータとインタラクション

メインプログラム                                   ジェネレータ関数
$g	 =	 gfunc();                             function	 gfunc(){
$ret	 =	 $g->send(1);                       	 	 $arg	 =	 yield;
$ret	 =	 $g->send(2);                       	 	 while	 (条件式)	 {
                                             14
$ret	 =	 $g->send(3);                       	 	 	 	 $ret	 =	 ...;
                                                 15
     12
                                            	 	 	 	 $arg	 =
                                            	 	 	 	 	 	 (yield	 $ret);
                                                     16
                                            	 	 	 	 var_dump($arg);
                                                 13
                                            	 	 }
                                            }

             copyright(c) 2012 kuwata-lab.com all rights reserved.
サンプル:数字あてゲーム
                            最初のsend()の引数値を変数に代入
1:	 function	 guess_quiz($num)	 {
2:	 	 	 	 $ans	 =	 yield;
3:	 	 	 	 while	 ($num	 !=	 $ans)	 {
4:	 	 	 	 	 	 	 if	 ($ans	 >	 $num)
5:	 	 	 	 	 	 	 	 	 	 $ans	 =	 (yield	 "too	 large");
6:	 	 	 	 	 	 	 else
7:	 	 	 	 	 	 	 	 	 	 $ans	 =	 (yield	 "too	 small");
8:	 	 	 	 }                     値を返し、かつsend()
9:	 }                           の引数値を変数に代入



                copyright(c) 2012 kuwata-lab.com all rights reserved.
サンプル:数字あてゲーム

1:	 $g	 =	 guess_quiz(mt_rand(1,	 100));
2:	 do	 {
3:	 	 	 	 echo	 "guess	 number	 (1-100):	 ";
4:	 	 	 	 $ans	 =	 fgets(STDIN,	 128);
5:	 	 	 	 if	 ($ans	 ===	 false)	 break;
6:	 	 	 	 $hint	 =	 $g->send($ans);
7:	 	 	 	 echo	 $hint	 ?	 $hint."n"
8:	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 :	 "Correct!n";
9:	 }	 while	 ($hint);                  値を送信し、かつ
                                                      次のyield文まで実行

               copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータとマルチスレッド

                                                                    Process
高機能



      機能は限られるが                                        Native Thread
      メモリ消費量が
      極めて少ない
      (=大量生成可能)
                                                 Green Thread

         Generator

                                                              リソース消費量
      : OSの機能として実現
      : 言語やライブラリで実現

            copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータと非同期処理

ネストしたコールバック関数
処理1(function($data)	 {
	 	 	 処理2(function($data)	 {
	 	 	 	 	 	 処理3(function($data)	 {
	 	 	 	 	 	 	 	 	 ....
	 	 	 	 	 	 });                                 読みにくい、
	 	 	 });                                       書きにくい、
});                                             わかりにくい




                    copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータと非同期処理

コールバック関数を数珠つなぎ
$d	 =	 new	 Deferred();
$d->next(function($data)	 {
	 	 	 	 	 	 ..処理1..;
})->next(function($data)	 {
	 	 	 	 	 	 ..処理2..;
})->next(function($data)	 {
	 	 	 	 	 	 ..処理3..;                                                記述量が多い、
                                                                    書き方が不自然
});


            copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータと非同期処理

ジェネレータ
function	 doSomething()	 {
	 	 	 $data	 =	 yield;
	 	 	 ...処理1...;
	 	 	 $data	 =	 yield;
	 	 	 ...処理2...;
	 	 	 $data	 =	 yield;
	 	 	 ...処理3...;          自然な書き方で
                          わかりやすい!
}


           copyright(c) 2012 kuwata-lab.com all rights reserved.
ジェネレータとページ遷移

1:	 $response	 =	 フォームを表示();
2:	 $request	 =	 (yield	 $response);
3:	 $response	 =	 プレビューを表示($request);
4:	 $request	 =	 (yield	 $response);
5:	 データベースに登録($request);

                               複数ページにまたがる遷移を
                               非同期処理と同じように記述 ※
                               (詳しくは「継続ベース フレームワーク」でggr)



※ Apache だとリクエストごとにすべてをリセットするので、実現できない。
  PHP のビルトイン Web サーバのようなパーシステントプロセスのサーバを使って、
 リクエストを超えてジェネレータオブジェクトを保持できるような仕組みが必要。
               copyright(c) 2012 kuwata-lab.com all rights reserved.
落とし穴:breakされた場合

	 1:	 function	 each_line($filename)	 {
	 2:	 	 	 	 $f	 =	 fopen($filename,	 'r');
	 3:	 	 	 	 $line	 =	 fgets($f);
	 4:	 	 	 	 while	 ($line	 !==	 FALSE)	 {
	 5:	 	 	 	 	 	 	 yield	 $line;
	 6:	 	 	 	 	 	 	 $line	 =	 fgets($f);
	 7:	 	 	 	 }
	 8:	 	 	 	 fclose($f);
	 9:	 }
                               呼び出し側でbreakされると
                                終了処理が行われない!※
                            (しかもPHPにはfinallyがないorz)

※ SPLFileObject も同じ問題を抱えているが、デストラクタで fclose() している。
                   copyright(c) 2012 kuwata-lab.com all rights reserved.
落とし穴:リファクタリング

奇数番目をyieldしてから、偶数番目をyieldする
	 1:	 function	 stepping($arr)	 {
	 2:	 	 	 	 $n	 =	 count($arr);
	 3:	 	 	 	 for	 ($i=0;	 $i<$n;	 $i+=2)
	 4:	 	 	 	 	 	 	 yield	 $arr[$i];
	 5:	 	 	 	 for	 ($i=1;	 $i<$n;	 $i+=2)
	 6:	 	 	 	 	 	 	 yield	 $arr[$i];
	 7:	 }
                                        DRYじゃない!関数化しよう!




              copyright(c) 2012 kuwata-lab.com all rights reserved.
落とし穴:リファクタリング

DRYになった、けど動かない!
	 1:	 function	 _sub($arr,	 $i,	 $n)	 {
	 2:	 	 	 	 for	 (;	 $i<$n;	 $i+=2)
	 3:	 	 	 	 	 	 	 yield	 $arr[$i];
	 4:	 }
	 5:	 function	 stepping($arr)	 {
	 6:	 	 	 	 $n	 =	 count($arr);
	 7:	 	 	 	 _sub($arr,	 0,	 $n);
	 8:	 	 	 	 _sub($arr,	 1,	 $n);
	 9:	 }
              ジェネレータ関数を呼び出して
              いるがforeach文を使ってない

              copyright(c) 2012 kuwata-lab.com all rights reserved.
落とし穴:リファクタリング

動くようになった…けどなんか腑に落ちない
	 1:	 function	 _sub($arr,	 $i,	 $n)	 {
	 2:	 	 	 	 for	 (;	 $i<$n;	 $i+=2)
	 3:	 	 	 	 	 	 	 yield	 $arr[$i];
	 4:	 }
	 5:	 function	 stepping($arr)	 {
	 6:	 	 	 	 $n	 =	 count($arr);
	 7:	 	 	 	 foreach	 (_sub($arr,	 0,	 $n)	 as	 $x)
	 8:	 	 	 	 	 	 	 yield	 $x;
	 9:	 	 	 	 foreach	 (_sub($arr,	 1,	 $n)	 as	 $x)
10:	 	 	 	 	 	 	 yield	 $x;
11:	 }
              copyright(c) 2012 kuwata-lab.com all rights reserved.
まとめ

◆ $->send()を使うと、双方向での値の受け渡し
  が可能
◆ マルチスレッドよりも低機能だが軽量
◆ 非同期処理が自然な形で記述できる
◆ 落とし穴もあるよ!




        copyright(c) 2012 kuwata-lab.com all rights reserved.
any questions?
おまけ
More Things




              copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:PHP5.5 コンパイル方法

$ git clone 
   https://github.com/nikic/php-src.git
$ cd php-src/
$ git checkout -b addGeneratorSupport 
   origin/addGeneratorSupport
$ ./buildconf
$ apxs2=/usr/local/apache2/bin/apxs
$ ./configure --with-apxs2=$apxs2
$ nice -20 time make
$ sapi/cli/php myexample.php


           copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:インデックスつきyield


	 1:	 function	 gfunc()	 {                                             //	 実行結果
	 2:	 	 	 	 yield	 'a';                                                0	 =>	 a
	 3:	 	 	 	 yield	 'b';                                                1	 =>	 b
	 4:	 	 	 	 yield	 99=>'c';                                            99	 =>	 c
	 5:	 }
	 6:	 
	 7:	 $g	 =	 gfunc();
	 8:	 foreach	 ($g	 as	 $k=>$v)	 {
	 9:	 	 	 echo	 "$k	 =>	 $v	 n";
10:	 }



               copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:参照渡しでのyield


	 1:	 function	 &gfunc(&$arr)	 {                                        //	 実行結果
	 2:	 	 	 foreach	 ($arr	 as	 &$x){                                     array(3)	 {
	 3:	 	 	 	 	 yield	 $x;                                                	 	 [0]=>
	 4:	 	 	 }                                                             	 	 int(11)
	 5:	 }                                                                 	 	 [1]=>
	 6:	                                                                   	 	 int(21)
	 7:	 $arr	 =	 [10,	 20,	 30];                                          	 	 [2]=>
	 8:	 $g	 =	 gfunc($arr);                                               	 	 &int(31)
	 9:	 foreach	 ($g	 as	 &$x)                                            }
10:	 	 	 $x	 +=	 1;
11:	 var_dump($arr);


                copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:クロージャとの比較

それ、クロージャでもできるよ!
function	 fib()	 {                              //	 使い方
	 	 list($x,	 $y)	 =                            $closure	 =	 fib();
	 	 	 	 [0,	 1];                                $x	 =	 $closure();
	 	 return	 function()                          while	 ($x	 <	 100)	 {
	 	 	 	 use	 ($x,	 $y)	 {                       	 	 echo	 $x,	 "n";
	 	 	 	 $tmp	 =	 $x;                            	 	 $x	 =	 $closure();
	 	 	 	 list($x,	 $y)	 =                        }
	 	 	 	 	 	 [$y,	 $x+$y];
	 	 	 	 return	 $tmp;
	 	 };
}


                 copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:クロージャとの比較

クロージャ版                                       ジェネレータ版
function	 fib()	 {                            function	 fib()	 {
	 	 list($x,	 $y)	 =                          	 	 list($x,	 $y)	 =
	 	 	 	 [0,	 1];                              	 	 	 	 [0,	 1];
	 	 return	 function()                        	 	 while	 (TRUE)	 {
	 	 	 	 use	 ($x,	 $y)	 {                     	 	 	 	 yield	 $x;
	 	 	 	 $tmp	 =	 $x;                          	 	 	 	 list($x,	 $y)	 =
	 	 	 	 list($x,	 $y)	 =                      	 	 	 	 	 	 [$y,	 $x+$y];
	 	 	 	 	 	 [$y,	 $x+$y];                     	 	 }
	 	 	 	 return	 $tmp;                         }
	 	 };
        ・毎回先頭から実行される                                    ・前回の終了場所から自動
}          制約                                            的に再開 (より自然な記述)
    ・すべてをreturnの前に書                                     ・yieldの後ろにも処理が書
      かなければならない制約                                        ける (より自然な記述)
               copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:内部イテレータとの比較

それ、内部イテレータでもできるよ!
function	 fib($fn)	 {                          //	 使い方
	 	 list($x,	 $y)	 =                           fib(function($x)	 {
	 	 	 	 [0,	 1];                               	 	 echo	 $x,	 "n";
	 	 while	 ($x	 <	 100)	 {                     });
	 	 	 	 $fn($x);
	 	 	 	 list($x,	 $y)	 =
	 	 	 	 	 	 [$y,	 $x+$y];
	 	 }
}




                copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:内部イテレータとの比較

ループの終了条件も指定したい場合は、非常にブサイク
function	 fib($c,$fn){                        //	 使い方          終了条件と…
	 	 list($x,	 $y)	 =                          fib(
	 	 	 	 [0,	 1];                              	 	 function($x)	 {
	 	 while	 ($c($x))	 {                        	 	 	 	 return	 $x	 <	 100;
	 	 	 	 $fn($x);                              	 	 },
	 	 	 	 list($x,	 $y)	 =                      	 	 function($x)	 {
	 	 	 	 	 	 [$y,	 $x+$y];                     	 	 	 	 echo	 $x,	 "n";
	 	 }                                         	 	 }
}                                             );       ボディ部の両方が必要




               copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:内部イテレータとの比較

可変箇所が複数ならジェネレータのほうがよっぽどきれい
function	 fib(){                                 //	 使い方
	 	 list($x,	 $y)	 =                             foreach(fib()	 as	 $x){
	 	 	 	 [0,	 1];                                 	 	 //	 終了条件
	 	 while	 (TRUE)	 {                             	 	 if	 ($x	 >=	 100)
	 	 	 	 yield	 $x;                               	 	 	 	 break;
	 	 	 	 list($x,	 $y)	 =                         	 	 //	 ボディ部
	 	 	 	 	 	 [$y,	 $x+$y];                        	 	 echo	 $x,	 "n";
	 	 }                                            };
}




                  copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:内部イテレータとの比較
Rubyでは、1つの無名関数 (ブロック) で「終了条件」と
「ボディ部」の両方を指定できる。

def	 fib()                                        //	 使い方
	 	 x,	 y	 =	 0,	 1                               fib	 {|x|
	 	 while	 true                                   	 	 //	 終了条件
	 	 	 	 yield	 x                                  	 	 break	 if	 x	 >=	 100
	 	 	 	 x,	 y	 =	 y,	 x+y                         	 	 //	 ボディ部
	 	 end                                           	 	 puts	 x
end                                               }




                   copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:「継続 (Continuation)」との比較

◆ 継続のほうができることが広い、
  ジェネレータはそのサブセット
                        ※
◆ 継続はcall stackを丸ごとコピーする ので重い、
  ジェネレータはstack flame1つだけなので軽い
◆ 継続は理解するのがすーーーっごく難しい、
  ジェネレータはわかりやすいし使いやすい




※処理系により実装方法は異なる場合がある

              copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:ベンチマーク
                                                        Code: https://gist.github.com/3710544

                                                                                 配列に詰め込む
          Loop                                                                   のは高コスト

          Array

    Generator

 Inner Iterator

       Closure
                  0                    0.2                       0.4                   0.6   0.8
                                                                                             (sec)



PHP: 5.5-addGeneratorSupport
OS: MacOSX
CPU: Core2DUO 2GHz
                               copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:ベンチマーク
                                                        Code: https://gist.github.com/3710569



          Loop                                      ジェネレータは
                                                    十分に低コスト
    Generator

G + explode()

G + explode()
   + array()
                  0                    0.5                         1                   1.5    2
                                                                                             (sec)

                                              ループ内処理 (explode()やarray())
                                              のほうがよっぽど高コスト
PHP: 5.5-addGeneratorSupport
OS: MacOSX
CPU: Core2DUO 2GHz
                               copyright(c) 2012 kuwata-lab.com all rights reserved.
おまけ:参考文献

◆ What PHP 5.5 might look like
   http://nikic.github.com/2012/07/10/What-PHP-5-5-might-look-like.html

◆ Request for Comments: Generators
   https://wiki.php.net/rfc/generators

◆ Scheme/継続の種類と利用例
   http://ja.wikibooks.org/wiki/Scheme/継続の種類と利用例

◆ Vallog - 継続の実装方針
   http://valvallow.blogspot.jp/2011/01/blog-post_11.html

◆ Twisted Intro: 「コールバック」ではない方法
  http://skitazaki.appspot.com/translation/twisted-intro-ja/p17.html

◆ 境界を越える: 継続とWeb開発、そしてJavaプログラミング
  http://www.ibm.com/developerworks/jp/java/library/j-cb03216/index.html


                          copyright(c) 2012 kuwata-lab.com all rights reserved.
おしまい

More Related Content

What's hot

AutoDock_vina_japanese_ver.3.0
AutoDock_vina_japanese_ver.3.0AutoDock_vina_japanese_ver.3.0
AutoDock_vina_japanese_ver.3.0Satoshi Kume
 
データモデリング・テクニック
データモデリング・テクニックデータモデリング・テクニック
データモデリング・テクニックHidekatsu Izuno
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?Moriharu Ohzu
 
Redmineをちょっと便利に! プログラミング無しで使ってみるREST API
Redmineをちょっと便利に! プログラミング無しで使ってみるREST APIRedmineをちょっと便利に! プログラミング無しで使ってみるREST API
Redmineをちょっと便利に! プログラミング無しで使ってみるREST APIGo Maeda
 
磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!Ra Zon
 
Xbyakの紹介とその周辺
Xbyakの紹介とその周辺Xbyakの紹介とその周辺
Xbyakの紹介とその周辺MITSUNARI Shigeo
 
Python製BDDツールで自動化してみた
Python製BDDツールで自動化してみたPython製BDDツールで自動化してみた
Python製BDDツールで自動化してみたKeijiUehata1
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~Miki Shimogai
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由kikairoya
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門Takuya Kitamura
 
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)Yoshiro Tokumasu
 
マスター・オブ・Reflectパッケージ
マスター・オブ・Reflectパッケージマスター・オブ・Reflectパッケージ
マスター・オブ・ReflectパッケージTakuya Ueda
 
Goの時刻に関するテスト
Goの時刻に関するテストGoの時刻に関するテスト
Goの時刻に関するテストKentaro Kawano
 
はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)Masatoshi Tada
 
実践的な設計って、なんだろう?
実践的な設計って、なんだろう?実践的な設計って、なんだろう?
実践的な設計って、なんだろう?増田 亨
 

What's hot (20)

AutoDock_vina_japanese_ver.3.0
AutoDock_vina_japanese_ver.3.0AutoDock_vina_japanese_ver.3.0
AutoDock_vina_japanese_ver.3.0
 
データモデリング・テクニック
データモデリング・テクニックデータモデリング・テクニック
データモデリング・テクニック
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
Jenkins with Docker
Jenkins with DockerJenkins with Docker
Jenkins with Docker
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 
Redmineをちょっと便利に! プログラミング無しで使ってみるREST API
Redmineをちょっと便利に! プログラミング無しで使ってみるREST APIRedmineをちょっと便利に! プログラミング無しで使ってみるREST API
Redmineをちょっと便利に! プログラミング無しで使ってみるREST API
 
磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!
 
Xbyakの紹介とその周辺
Xbyakの紹介とその周辺Xbyakの紹介とその周辺
Xbyakの紹介とその周辺
 
No-Ops で大量データ処理基盤
No-Ops で大量データ処理基盤No-Ops で大量データ処理基盤
No-Ops で大量データ処理基盤
 
Python製BDDツールで自動化してみた
Python製BDDツールで自動化してみたPython製BDDツールで自動化してみた
Python製BDDツールで自動化してみた
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
CQRS+ES on GCP
CQRS+ES on GCPCQRS+ES on GCP
CQRS+ES on GCP
 
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門
 
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)
 
マスター・オブ・Reflectパッケージ
マスター・オブ・Reflectパッケージマスター・オブ・Reflectパッケージ
マスター・オブ・Reflectパッケージ
 
Goの時刻に関するテスト
Goの時刻に関するテストGoの時刻に関するテスト
Goの時刻に関するテスト
 
はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)
 
実践的な設計って、なんだろう?
実践的な設計って、なんだろう?実践的な設計って、なんだろう?
実践的な設計って、なんだろう?
 

Similar to PHP5.5新機能「ジェネレータ」初心者入門

ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】株式会社ランチェスター
 
Hack/HHVM 入門
Hack/HHVM 入門Hack/HHVM 入門
Hack/HHVM 入門y-uti
 
Clojure programming-chapter-2
Clojure programming-chapter-2Clojure programming-chapter-2
Clojure programming-chapter-2Masao Kato
 
Perl 非同期プログラミング
Perl 非同期プログラミングPerl 非同期プログラミング
Perl 非同期プログラミングlestrrat
 
最近の PHP の話
最近の PHP の話最近の PHP の話
最近の PHP の話y-uti
 
ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~
ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~
ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~Akabane Hiroyuki
 
Grails-1.1を斬る!~Grails-1.1からのチーム開発~ in Tokyo
Grails-1.1を斬る!~Grails-1.1からのチーム開発~ in TokyoGrails-1.1を斬る!~Grails-1.1からのチーム開発~ in Tokyo
Grails-1.1を斬る!~Grails-1.1からのチーム開発~ in TokyoTsuyoshi Yamamoto
 
PHPの今とこれから2014
PHPの今とこれから2014PHPの今とこれから2014
PHPの今とこれから2014Rui Hirokawa
 
今日からはじめるGPars
今日からはじめるGPars今日からはじめるGPars
今日からはじめるGParsfumokmm
 
PHPBLT#6 PHPの未来に入るかもしれない機能の紹介
PHPBLT#6 PHPの未来に入るかもしれない機能の紹介PHPBLT#6 PHPの未来に入るかもしれない機能の紹介
PHPBLT#6 PHPの未来に入るかもしれない機能の紹介sters
 
Node.js - JavaScript Thread Programming
Node.js - JavaScript Thread ProgrammingNode.js - JavaScript Thread Programming
Node.js - JavaScript Thread Programmingtakesako
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-Kazunari Hara
 
PHPの今とこれから2019
PHPの今とこれから2019PHPの今とこれから2019
PHPの今とこれから2019Rui Hirokawa
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」yoshiaki iwanaga
 

Similar to PHP5.5新機能「ジェネレータ」初心者入門 (20)

ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
ちょっと詳しくJavaScript 第4回【スコープとクロージャ】
 
Hack/HHVM 入門
Hack/HHVM 入門Hack/HHVM 入門
Hack/HHVM 入門
 
Clojure programming-chapter-2
Clojure programming-chapter-2Clojure programming-chapter-2
Clojure programming-chapter-2
 
test
testtest
test
 
Perl 非同期プログラミング
Perl 非同期プログラミングPerl 非同期プログラミング
Perl 非同期プログラミング
 
最近の PHP の話
最近の PHP の話最近の PHP の話
最近の PHP の話
 
0x300
0x3000x300
0x300
 
PHP7を魔改造した話
PHP7を魔改造した話PHP7を魔改造した話
PHP7を魔改造した話
 
ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~
ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~
ビギナーだから使いたいO/Rマッパー ~Tengを使った開発~
 
Grails-1.1を斬る!~Grails-1.1からのチーム開発~ in Tokyo
Grails-1.1を斬る!~Grails-1.1からのチーム開発~ in TokyoGrails-1.1を斬る!~Grails-1.1からのチーム開発~ in Tokyo
Grails-1.1を斬る!~Grails-1.1からのチーム開発~ in Tokyo
 
PHP language update 201211
PHP language update 201211PHP language update 201211
PHP language update 201211
 
OSC京都2011
OSC京都2011OSC京都2011
OSC京都2011
 
PHPの今とこれから2014
PHPの今とこれから2014PHPの今とこれから2014
PHPの今とこれから2014
 
今日からはじめるGPars
今日からはじめるGPars今日からはじめるGPars
今日からはじめるGPars
 
PHPBLT#6 PHPの未来に入るかもしれない機能の紹介
PHPBLT#6 PHPの未来に入るかもしれない機能の紹介PHPBLT#6 PHPの未来に入るかもしれない機能の紹介
PHPBLT#6 PHPの未来に入るかもしれない機能の紹介
 
Node.js - JavaScript Thread Programming
Node.js - JavaScript Thread ProgrammingNode.js - JavaScript Thread Programming
Node.js - JavaScript Thread Programming
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
 
Try Jetpack
Try JetpackTry Jetpack
Try Jetpack
 
PHPの今とこれから2019
PHPの今とこれから2019PHPの今とこれから2019
PHPの今とこれから2019
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
 

More from kwatch

How to make the fastest Router in Python
How to make the fastest Router in PythonHow to make the fastest Router in Python
How to make the fastest Router in Pythonkwatch
 
Migr8.rb チュートリアル
Migr8.rb チュートリアルMigr8.rb チュートリアル
Migr8.rb チュートリアルkwatch
 
なんでもID
なんでもIDなんでもID
なんでもIDkwatch
 
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方kwatch
 
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方kwatch
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐkwatch
 
正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?kwatch
 
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)kwatch
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!kwatch
 
PHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較するPHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較するkwatch
 
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?kwatch
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Pythonkwatch
 
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策kwatch
 
Pretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/MercurialPretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/Mercurialkwatch
 
Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -kwatch
 
文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみたkwatch
 
I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"kwatch
 
Cより速いRubyプログラム
Cより速いRubyプログラムCより速いRubyプログラム
Cより速いRubyプログラムkwatch
 
Javaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジンJavaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジンkwatch
 
Underlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R MapperUnderlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R Mapperkwatch
 

More from kwatch (20)

How to make the fastest Router in Python
How to make the fastest Router in PythonHow to make the fastest Router in Python
How to make the fastest Router in Python
 
Migr8.rb チュートリアル
Migr8.rb チュートリアルMigr8.rb チュートリアル
Migr8.rb チュートリアル
 
なんでもID
なんでもIDなんでもID
なんでもID
 
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
 
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
 
正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?
 
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!
 
PHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較するPHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較する
 
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Python
 
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
 
Pretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/MercurialPretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/Mercurial
 
Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -
 
文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた
 
I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"
 
Cより速いRubyプログラム
Cより速いRubyプログラムCより速いRubyプログラム
Cより速いRubyプログラム
 
Javaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジンJavaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジン
 
Underlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R MapperUnderlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R Mapper
 

Recently uploaded

TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案sugiuralab
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfFumieNakayama
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfFumieNakayama
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...博三 太田
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)UEHARA, Tetsutaro
 

Recently uploaded (12)

TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
TataPixel: 畳の異方性を利用した切り替え可能なディスプレイの提案
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdfAWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
AWS の OpenShift サービス (ROSA) を使った OpenShift Virtualizationの始め方.pdf
 
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdfクラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
クラウドネイティブなサーバー仮想化基盤 - OpenShift Virtualization.pdf
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察  ~Text-to-MusicとText-To-ImageかつImage-to-Music...
モーダル間の変換後の一致性とジャンル表を用いた解釈可能性の考察 ~Text-to-MusicとText-To-ImageかつImage-to-Music...
 
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
デジタル・フォレンジックの最新動向(2024年4月27日情洛会総会特別講演スライド)
 

PHP5.5新機能「ジェネレータ」初心者入門

  • 1. PHPカンファレンス2012 PHP5.5新機能 かもしれない Generator 初心者入門 makoto kuwata <kwa@kuwata-lab.com> http://www.kuwata-lab.com/ 2012-09-15 (Sat) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 2. 本発表について 【目的】 • PHP5.5の新機能かもしれない「ジェネレータ」を、 「なんだか凄そうだ」と思ってもらう。 【内容】 • ジェネレータって何? • どううれしいの? • どんなことに使えるの? 【注意】 • 内容は2012-09-15時点での情報に基づく。 今後、仕様変更があり得るので注意。 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 3. ジェネレータって何? What is Generator? copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 4. まとめ ◆ ジェネレータ セーブ機能 ◆ ジェネレータ関数 ゲームシナリオ ◆ ジェネレータオブジェクト 冒険の書 (セーブデータ) ◆ yield文 宿屋(セーブポイント) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 5. 通常の関数 1: function func() { 2: $i = 0; 1, 2, 3回目 (0が返される) 3: return $i; 4: $i++; 5: return $i; 6: $i++; 7: return $i; 8: } 毎回先頭から実行され、また return文より後ろは実行されない copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 6. ジェネレータ (Generator) 関数 1: function gfunc() { 2: $i = 0; 1回目 (0が返される) 3: yield $i; 4: $i++; 5: yield $i; 2回目 (1が返される) 6: $i++; 7: yield $i; 3回目 (2が返される) 8: } 前回の終了位置から再開 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 7. 使い方 ジェネレータオブジェクトを生成 (通常の関数と使い方が違うことに注意!) 1: $g = gfunc(); 2: foreach ($g as $x) { 3: var_dump($x); 4: } foreach文とともに使用 (イテレータとして振る舞う) 実行例 int(0) int(1) int(2) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 8. 実行順序:ループ1回目 メインプログラム ジェネレータ関数 1 $g = gfunc(); function gfunc(){ 2 foreach($g as $x){ $i = 0; 3 var_dump($x); yield $i; 4 5 } $i++; echo "donen"; yield $i; $i++; return $i; } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 9. 実行順序:ループ2回目 メインプログラム ジェネレータ関数 $g = gfunc(); function gfunc(){ 6 foreach($g as $x){ $i = 0; var_dump($x); yield $i; 9 } $i++; 7 echo "donen"; yield $i; 8 $i++; return $i; } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 10. 実行順序:ループ3回目…は、ない メインプログラム ジェネレータ関数 $g = gfunc(); function gfunc(){ 10foreach($g as $x){ $i = 0; var_dump($x); yield $i; } $i++; yield $i; 13echo "donen"; $i++; 11 return $i; 12 ・ループのたびにyield文まで実行 ・yield文の引数がループ変数に } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 11. サンプル:2つの値を交互に出力 1: function toggle($odd, $even) { 2: while (TRUE) { 3: yield $odd; 4: yield $even; 5: } 6: } 7: 8: // "red" と "blue" を交互に出力 9: foreach (toggle("red", "blue") as $c){ 10: echo $c, "n"; // 無限に出力 11: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 12. サンプル:フィボナッチ数列 (0, 1, 1, 2, 3, 5, 8, 13,...) 1: function fib() { 2: $x = 0; $y = 1; コツ:ループの終了条件を 3: while (TRUE) { 指定しない (無限ループ) 4: yield $x; 5: list($x, $y) = [$y, $x+$y]; 6: } 7: } 8: 9: // 100未満のフィボナッチ数列を出力 10: foreach (fib() as $x) { 11: if ($x >= 100) break; 12: echo $x, "n"; コツ:終了条件は呼 13: } び出す側で指定する copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 13. まとめ ◆ ジェネレータ セーブ機能 ◆ ジェネレータ関数 ゲームシナリオ ◆ ジェネレータオブジェクト 冒険の書 (セーブデータ) ◆ yield文 宿屋(セーブポイント) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 14. どううれしいの? Why Generator is so useful? copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 15. Before: ファイルを1行ずつ処理する 1: // 行番号つきで表示 2: $f = fopen($filename, 'r'); 3: if ($f === FALSE) throw ....; 4: $line = fgets($f); 5: while ($line !== FALSE) { 6: ++$i; 7: echo $i, ": ", $line; 8: $line = fgets($f); 9: } 10: fclose($f); 11: copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 16. Before: ファイルを1行ずつ処理する 1: // パターンで絞り込む 2: $f = fopen($filename, 'r'); 3: if ($f === FALSE) throw ....; 4: $line = fgets($f); 5: while ($line !== FALSE) { 6: if (preg_match('/@/', $line)) 7: echo $line; 8: $line = fgets($f); 9: } 10: fclose($f); 11: copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 17. Before: ファイルを1行ずつ処理する 1: // タブ文字でフィールドに分解 2: $f = fopen($filename, 'r'); 3: if ($f === FALSE) throw ....; 4: $line = fgets($f); 5: while ($line !== FALSE) { 6: $arr = explode("t", $line); 7: echo $arr[1], "n"; 8: $line = fgets($f); 9: } 汎用性の高いコードの中に 10: fclose($f); 汎用性の低いコードが混在 11: copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 18. After: ジェネレータ関数 汎用性の高い箇所を関数に抽出 1: function each_line($filename) { 2: $f = fopen($filename, 'r'); 3: if ($f === FALSE) throw ....; 4: $line = fgets($f); 5: while ($line !== FALSE) { 6: $arr = explode("t", $line); yield $line; 7: echo $arr[1]; 汎用性の低い箇所を yield 文に 8: $line = fgets($f); 9: } 10: fclose($f); 11: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 19. After: メインプログラム 1: // ジェネレータオブジェクトを生成 2: $g = each_line($filename); 3: // メインループ 4: foreach ($g as $line) { 5: // 汎用性の低い処理 6: $arr = explode("t", $line); 7: echo $arr[1], "n"; 8: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 20. ジェネレータの利点 ◆ ループ処理から、汎用性の高い箇所だけを切り 出せる(再利用性の向上) ◆ ◆ ◆ copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 21. もっとジェネレータ関数 ジェネレータオブジェクトを受け取り、新し い別のジェネレータオブジェクトを生成する 1: // ジェネレータオブジェクトを作成 受け取る function each_fields($g) { 2: $g = each_line($filename); 3: // ループ 配列やイテレータでも可 4: foreach ($g as $line) { 5: $arr = explode("t", $line); 6: echo $arr[1]; yield $arr; 7: } 8: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 22. ジェネレータを「重ねる」 1: // ジェネレータオブジェクトを生成 2: $g = each_line($filename); 3: $g = each_fields($g); ジェネレータから 4: // メインループ 別のジェネレータ 5: foreach ($g as $line) { を生成 $arr 6: $arr = explode("n", $line);                     7: echo $arr[1], "n"; 8: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 23. 1つの大きなループ vs. 複数の小さなループ ジェネレータ使用前 ジェネレータ使用後 $f = fopen($filename, 'r'); while ($line !== FALSE) { $line = fgets($f); yield $line; while ($line !== FALSE) { } $arr = explode("n",$line); echo $arr[1]; foreach ($g as $line) { $line = fgets($f); yield $arr; } } fclose($f); $g = each_line($filename); $g = each_fields($g); foreach ($g as $arr) { echo $arr[1], "n"; } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 24. ジェネレータの利点 ◆ ループ処理から、汎用性の高い箇所だけを切り 出せる(再利用性の向上) ◆ ひとつの大きなループを、複数の小さなループ に分解できる(ループの簡素化とPipeline化) ◆ ◆ copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 25. 従来方法との比較:配列にすべて格納する 1: function each_line($filename) { 2: $f = fopen($filename, 'r'); 3: $lines = array(); メモリを大量に消費 4: $line = fgets($f);(巨大データだと落ちる) 5: while ($line !== FALSE) { 6: $lines[] = $line; 7: $line = fgets($f); 8: } 9: fclose($f); すべてを読み込まないと 10: return $lines; 結果が返ってこない 11: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 26. 従来方法との比較:ジェネレータ 1: function each_line($filename) { 2: $f = fopen($filename, 'r'); 3: 1度に1行しか読み込まない 4: $line = fgets($f); (巨大なデータでも落ちない) 5: while ($line !== FALSE) { 6: yield $line; 7: $line = fgets($f); 8: } 読み込んだはしから値を返す 9: fclose($f); (ストリーム処理に最適) 10 11: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 27. リダイレクト v.s. パイプライン すべてを配列に格納する ≒「リダイレクト」 ・巨大な中間ファイルが必要 ・最後まで処理しないと何も出力されない bash% command1 < input > tmp1 bash% command2 < tmp1 > tmp2 bash% command3 < tmp2 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 28. リダイレクト v.s. パイプライン ジェネレータを連結する ≒ 「パイプ」 ・巨大な中間ファイルがいらない ・読み込んだはしから出力される bash% cat input | command1 | command2 | command3 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 29. ジェネレータの利点 ◆ ループ処理から、汎用性の高い箇所だけを切り 出せる(再利用性の向上) ◆ ひとつの大きなループを、複数の小さなループ に分解できる(ループの簡素化とPipeline化) ◆ メモリ消費量が少ない (巨大なデータを扱ってもプロセスが落ちない) ◆ データを読んだはしから処理できる (ストリームデータも処理可能) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 30. どんな使い道があるの? Advanced Generator copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 31. ジェネレータとインタラクション $g->send() … 次のyield文まで実行する メインプログラム ジェネレータ関数 からメインプログ ラムに値を返す foreach(){} yield $value $g->send($arg) メインプログラム ジェネレータ関数 からジェネレータ 関数に値を渡せる copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 32. ジェネレータとインタラクション 双方向への値の受け渡しが可能に メインプログラム $value = $g->send("arg"); send()の引数が yield文の値に yield文の引数が send()の戻り値に ジェネレータ関数 $arg = (yield "value"); copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 33. ジェネレータとインタラクション メインプログラム ジェネレータ関数 1$g = gfunc(); function gfunc(){ $ret = $g->send(1); $arg = yield; 2 3 $ret = $g->send(2); while (条件式) { 4 $ret = $g->send(3); $ret = ...; 5 $arg = (yield $ret); 6 var_dump($arg); } } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 34. ジェネレータとインタラクション メインプログラム ジェネレータ関数 $g = gfunc(); function gfunc(){ $ret = $g->send(1); $arg = yield; $ret = $g->send(2); while (条件式) { 9 7 $ret = $g->send(3); $ret = ...; 10 $arg = (yield $ret); 11 var_dump($arg); 8 } } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 35. ジェネレータとインタラクション メインプログラム ジェネレータ関数 $g = gfunc(); function gfunc(){ $ret = $g->send(1); $arg = yield; $ret = $g->send(2); while (条件式) { 14 $ret = $g->send(3); $ret = ...; 15 12 $arg = (yield $ret); 16 var_dump($arg); 13 } } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 36. サンプル:数字あてゲーム 最初のsend()の引数値を変数に代入 1: function guess_quiz($num) { 2: $ans = yield; 3: while ($num != $ans) { 4: if ($ans > $num) 5: $ans = (yield "too large"); 6: else 7: $ans = (yield "too small"); 8: } 値を返し、かつsend() 9: } の引数値を変数に代入 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 37. サンプル:数字あてゲーム 1: $g = guess_quiz(mt_rand(1, 100)); 2: do { 3: echo "guess number (1-100): "; 4: $ans = fgets(STDIN, 128); 5: if ($ans === false) break; 6: $hint = $g->send($ans); 7: echo $hint ? $hint."n" 8: : "Correct!n"; 9: } while ($hint); 値を送信し、かつ 次のyield文まで実行 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 38. ジェネレータとマルチスレッド Process 高機能 機能は限られるが Native Thread メモリ消費量が 極めて少ない (=大量生成可能) Green Thread Generator リソース消費量 : OSの機能として実現 : 言語やライブラリで実現 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 39. ジェネレータと非同期処理 ネストしたコールバック関数 処理1(function($data) { 処理2(function($data) { 処理3(function($data) { .... }); 読みにくい、 }); 書きにくい、 }); わかりにくい copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 40. ジェネレータと非同期処理 コールバック関数を数珠つなぎ $d = new Deferred(); $d->next(function($data) { ..処理1..; })->next(function($data) { ..処理2..; })->next(function($data) { ..処理3..; 記述量が多い、 書き方が不自然 }); copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 41. ジェネレータと非同期処理 ジェネレータ function doSomething() { $data = yield; ...処理1...; $data = yield; ...処理2...; $data = yield; ...処理3...; 自然な書き方で わかりやすい! } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 42. ジェネレータとページ遷移 1: $response = フォームを表示(); 2: $request = (yield $response); 3: $response = プレビューを表示($request); 4: $request = (yield $response); 5: データベースに登録($request); 複数ページにまたがる遷移を 非同期処理と同じように記述 ※ (詳しくは「継続ベース フレームワーク」でggr) ※ Apache だとリクエストごとにすべてをリセットするので、実現できない。 PHP のビルトイン Web サーバのようなパーシステントプロセスのサーバを使って、 リクエストを超えてジェネレータオブジェクトを保持できるような仕組みが必要。 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 43. 落とし穴:breakされた場合 1: function each_line($filename) { 2: $f = fopen($filename, 'r'); 3: $line = fgets($f); 4: while ($line !== FALSE) { 5: yield $line; 6: $line = fgets($f); 7: } 8: fclose($f); 9: } 呼び出し側でbreakされると 終了処理が行われない!※ (しかもPHPにはfinallyがないorz) ※ SPLFileObject も同じ問題を抱えているが、デストラクタで fclose() している。 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 44. 落とし穴:リファクタリング 奇数番目をyieldしてから、偶数番目をyieldする 1: function stepping($arr) { 2: $n = count($arr); 3: for ($i=0; $i<$n; $i+=2) 4: yield $arr[$i]; 5: for ($i=1; $i<$n; $i+=2) 6: yield $arr[$i]; 7: } DRYじゃない!関数化しよう! copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 45. 落とし穴:リファクタリング DRYになった、けど動かない! 1: function _sub($arr, $i, $n) { 2: for (; $i<$n; $i+=2) 3: yield $arr[$i]; 4: } 5: function stepping($arr) { 6: $n = count($arr); 7: _sub($arr, 0, $n); 8: _sub($arr, 1, $n); 9: } ジェネレータ関数を呼び出して いるがforeach文を使ってない copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 46. 落とし穴:リファクタリング 動くようになった…けどなんか腑に落ちない 1: function _sub($arr, $i, $n) { 2: for (; $i<$n; $i+=2) 3: yield $arr[$i]; 4: } 5: function stepping($arr) { 6: $n = count($arr); 7: foreach (_sub($arr, 0, $n) as $x) 8: yield $x; 9: foreach (_sub($arr, 1, $n) as $x) 10: yield $x; 11: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 47. まとめ ◆ $->send()を使うと、双方向での値の受け渡し が可能 ◆ マルチスレッドよりも低機能だが軽量 ◆ 非同期処理が自然な形で記述できる ◆ 落とし穴もあるよ! copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 49. おまけ More Things copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 50. おまけ:PHP5.5 コンパイル方法 $ git clone https://github.com/nikic/php-src.git $ cd php-src/ $ git checkout -b addGeneratorSupport origin/addGeneratorSupport $ ./buildconf $ apxs2=/usr/local/apache2/bin/apxs $ ./configure --with-apxs2=$apxs2 $ nice -20 time make $ sapi/cli/php myexample.php copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 51. おまけ:インデックスつきyield 1: function gfunc() { // 実行結果 2: yield 'a'; 0 => a 3: yield 'b'; 1 => b 4: yield 99=>'c'; 99 => c 5: } 6: 7: $g = gfunc(); 8: foreach ($g as $k=>$v) { 9: echo "$k => $v n"; 10: } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 52. おまけ:参照渡しでのyield 1: function &gfunc(&$arr) { // 実行結果 2: foreach ($arr as &$x){ array(3) { 3: yield $x; [0]=> 4: } int(11) 5: } [1]=> 6: int(21) 7: $arr = [10, 20, 30]; [2]=> 8: $g = gfunc($arr); &int(31) 9: foreach ($g as &$x) } 10: $x += 1; 11: var_dump($arr); copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 53. おまけ:クロージャとの比較 それ、クロージャでもできるよ! function fib() { // 使い方 list($x, $y) = $closure = fib(); [0, 1]; $x = $closure(); return function() while ($x < 100) { use ($x, $y) { echo $x, "n"; $tmp = $x; $x = $closure(); list($x, $y) = } [$y, $x+$y]; return $tmp; }; } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 54. おまけ:クロージャとの比較 クロージャ版 ジェネレータ版 function fib() { function fib() { list($x, $y) = list($x, $y) = [0, 1]; [0, 1]; return function() while (TRUE) { use ($x, $y) { yield $x; $tmp = $x; list($x, $y) = list($x, $y) = [$y, $x+$y]; [$y, $x+$y]; } return $tmp; } }; ・毎回先頭から実行される ・前回の終了場所から自動 } 制約 的に再開 (より自然な記述) ・すべてをreturnの前に書 ・yieldの後ろにも処理が書 かなければならない制約 ける (より自然な記述) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 55. おまけ:内部イテレータとの比較 それ、内部イテレータでもできるよ! function fib($fn) { // 使い方 list($x, $y) = fib(function($x) { [0, 1]; echo $x, "n"; while ($x < 100) { }); $fn($x); list($x, $y) = [$y, $x+$y]; } } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 56. おまけ:内部イテレータとの比較 ループの終了条件も指定したい場合は、非常にブサイク function fib($c,$fn){ // 使い方 終了条件と… list($x, $y) = fib( [0, 1]; function($x) { while ($c($x)) { return $x < 100; $fn($x); }, list($x, $y) = function($x) { [$y, $x+$y]; echo $x, "n"; } } } ); ボディ部の両方が必要 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 57. おまけ:内部イテレータとの比較 可変箇所が複数ならジェネレータのほうがよっぽどきれい function fib(){ // 使い方 list($x, $y) = foreach(fib() as $x){ [0, 1]; // 終了条件 while (TRUE) { if ($x >= 100) yield $x; break; list($x, $y) = // ボディ部 [$y, $x+$y]; echo $x, "n"; } }; } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 58. おまけ:内部イテレータとの比較 Rubyでは、1つの無名関数 (ブロック) で「終了条件」と 「ボディ部」の両方を指定できる。 def fib() // 使い方 x, y = 0, 1 fib {|x| while true // 終了条件 yield x break if x >= 100 x, y = y, x+y // ボディ部 end puts x end } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 59. おまけ:「継続 (Continuation)」との比較 ◆ 継続のほうができることが広い、 ジェネレータはそのサブセット ※ ◆ 継続はcall stackを丸ごとコピーする ので重い、 ジェネレータはstack flame1つだけなので軽い ◆ 継続は理解するのがすーーーっごく難しい、 ジェネレータはわかりやすいし使いやすい ※処理系により実装方法は異なる場合がある copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 60. おまけ:ベンチマーク Code: https://gist.github.com/3710544 配列に詰め込む Loop のは高コスト Array Generator Inner Iterator Closure 0 0.2 0.4 0.6 0.8 (sec) PHP: 5.5-addGeneratorSupport OS: MacOSX CPU: Core2DUO 2GHz copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 61. おまけ:ベンチマーク Code: https://gist.github.com/3710569 Loop ジェネレータは 十分に低コスト Generator G + explode() G + explode() + array() 0 0.5 1 1.5 2 (sec) ループ内処理 (explode()やarray()) のほうがよっぽど高コスト PHP: 5.5-addGeneratorSupport OS: MacOSX CPU: Core2DUO 2GHz copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 62. おまけ:参考文献 ◆ What PHP 5.5 might look like http://nikic.github.com/2012/07/10/What-PHP-5-5-might-look-like.html ◆ Request for Comments: Generators https://wiki.php.net/rfc/generators ◆ Scheme/継続の種類と利用例 http://ja.wikibooks.org/wiki/Scheme/継続の種類と利用例 ◆ Vallog - 継続の実装方針 http://valvallow.blogspot.jp/2011/01/blog-post_11.html ◆ Twisted Intro: 「コールバック」ではない方法 http://skitazaki.appspot.com/translation/twisted-intro-ja/p17.html ◆ 境界を越える: 継続とWeb開発、そしてJavaプログラミング http://www.ibm.com/developerworks/jp/java/library/j-cb03216/index.html copyright(c) 2012 kuwata-lab.com all rights reserved.