※メモ程度のコードです。
ジェネレータ
(PHP 5 >= 5.5.0, PHP 7)
概略
- PHP5.5から導入された
- yield を return の代わりに記述することでループの中で都度値を返却できる
ある共通処理を関数化した際、配列Aを配列Bに代入してゴニョゴニョ・・など2つ配列を作ることでメモリを食ってしまうのをジェネレータ構文を使うことで改善できる(ことがある)
構文
generator.php
<?php
echo "-------basic_sample_1--------\n";
/*ベーシックなサンプル その1
1から3までの数値を出力する*/
function basic_sample_1 ()
{
$i = 0; //初回は 0
// yieldは終了ではなく保存ポイント
yield $i; //保存ポイント! 値を一旦戻す 0
//一回目ここまで ↑
//二回目ここから ↓
$i++; //2回目 プラス 1
yield $i; //保存ポイント! 値を一旦戻す 1
//二回目ここまで ↑
//三回目ここから ↓
$i++; //2回目 プラス 1
yield $i; //保存ポイント! 値を一旦戻す 2
//三回目ここまで ↑
}
// 前回の終了位置から、実行を再開できる
//ジェネレーターオブジェクトを生成する
$generator = basic_sample_1();
foreach ($generator as $x) {
// yield文の引数($i)がループ変数になる
var_dump($x);
}
/*
結果
int(0)
int(1)
int(2)
*/
echo "-------while_sample--------\n";
/* while文を用いたサンプル
1から10までの数値を順に出力する*/
function while_sample()
{
$i = 0;
//ジェネレータ側では終了条件は指定しない
while(true) {
$i++;
yield $i; //保存ポイント! 値を一旦戻す
}
}
$generator = while_sample();
foreach($generator as $x) {
var_dump($x);
//終了条件は呼び出し側で指定する
if ($x >= 10) {
break;
}
}
/*
結果
int(1)
int(2)
int(3)
int(4)
int(5)
int(6)
int(7)
int(8)
int(9)
int(10)
*/
echo "-------generator recursive--------\n";
/*
ジェネレータからジェネレータを呼ぶ例
CSVファイルに見立てた配列を一行ずつフィールドも分けた状態で配列に格納する
*/
$file = array(
'john,banana,water',
'mike,apple,milk',
'fredy,orange,coffee',
);
//1行ずつ読み込み
function each_record($file)
{
foreach ($file as $v) {
yield $v;
}
}
//1行を更にカンマで分ける
function each_field($generator)
{
foreach ($generator as $v) {
$field_array = explode(',', $v);
yield $field_array;
}
}
$generator = each_record($file);
$generator = each_field($generator);
foreach($generator as $v) {
$new_array[] = $v;
}
var_dump($new_array);
/*
結果
array(3) {
[0]=>
array(3) {
[0]=>
string(4) "john"
[1]=>
string(6) "banana"
[2]=>
string(5) "water"
}
[1]=>
array(3) {
[0]=>
string(4) "mike"
[1]=>
string(5) "apple"
[2]=>
string(4) "milk"
}
[2]=>
array(3) {
[0]=>
string(5) "fredy"
[1]=>
string(6) "orange"
[2]=>
string(6) "coffee"
}
}
*/
echo "-------merge using generator--------\n";
// この配列が巨大だった場合、単純にforeachで回すとメモリを食う
$arr1 = array(
array('hoge1' => 'fuga1'),
array('hoge2' => 'fuga2'),
array('hoge3' => 'fuga3'),
array('hoge4' => 'fuga4'),
);
$arr2 = array(
array('foo1' => 'bar1'),
array('foo2' => 'bar2'),
array('foo3' => 'bar3'),
array('foo4' => 'bar4'),
);
function arr1_parser($arr1)
{
foreach ($arr1 as $value) {
yield $value;
}
}
$generator = arr1_parser($arr1);
foreach ($generator as $key => $value) {
var_dump(array_merge($value, $arr2[$key]));
}
/*
結果
array(2) {
["hoge1"]=>
string(5) "fuga1"
["foo1"]=>
string(4) "bar1"
}
array(2) {
["hoge2"]=>
string(5) "fuga2"
["foo2"]=>
string(4) "bar2"
}
array(2) {
["hoge3"]=>
string(5) "fuga3"
["foo3"]=>
string(4) "bar3"
}
array(2) {
["hoge4"]=>
string(5) "fuga4"
["foo4"]=>
string(4) "bar4"
}
*/