ジェネレータとは

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

ジェネレータを使えば、シンプルな イテレータを簡単に実装できます。 Iterator インターフェイスを実装したクラスを用意する オーバーヘッドや複雑さを心配する必要はありません。

ジェネレータを使うと、foreach でデータ群を順に処理するコードを書くときに メモリ内で配列を組み立てなくても済むようになります。 メモリ内で配列を組み立てると memory_limit を越えてしまうかもしれないし、 無視できないほどの時間がかかってしまうかもしれません。 配列を作る代わりに、ジェネレータ関数を書くことになります。これは通常の 関数と同じものですが、 ジェネレータ関数は一度だけ return するのではなく、必要に応じて何度でも yield することができます。 つまり、値を繰り返し返せるということです。

シンプルな例として、range() 関数をジェネレータで実装しなおしてみましょう。 標準の range() 関数は、すべての値を含む配列を作ってそれを返します。 結果的に、かなり大きな配列になる可能性があります。たとえば range(0, 1000000) を実行すると、 100 MB を超えるメモリを使うことになります。

その代替として、ジェネレータ xrange() を実装します。 必要なメモリは、Iterator オブジェクトを作ってジェネレータの内部の状態を記録しておくのに必要なものだけになります。 1 KB 未満で収まるでしょう。

例1 ジェネレータを使った range() の実装

<?php
function xrange($start, $limit, $step = 1) {
if (
$start <= $limit) {
if (
$step <= 0) {
throw new
LogicException('Step must be positive');
}

for (
$i = $start; $i <= $limit; $i += $step) {
yield
$i;
}
} else {
if (
$step >= 0) {
throw new
LogicException('Step must be negative');
}

for (
$i = $start; $i >= $limit; $i += $step) {
yield
$i;
}
}
}



echo 'Single digit odd numbers from range(): ';
foreach (
range(1, 9, 2) as $number) {
echo
"$number ";
}
echo
"\n";

echo
'Single digit odd numbers from xrange(): ';
foreach (
xrange(1, 9, 2) as $number) {
echo
"$number ";
}
?>

上の例の出力は以下となります。

 Single digit odd numbers from range(): 1 3 5 7 9 Single digit odd numbers from xrange(): 1 3 5 7 9 

Generator オブジェクト

ジェネレータ関数を呼んだときには、内部クラス Generator の新しいオブジェクトを返します。 このオブジェクトは Iterator インターフェイスを実装しており、 前進しかできないイテレータオブジェクトと同じように振る舞います。 そして、このオブジェクトが提供するメソッドを使えば、 値を送ったり戻したりなどしてジェネレータの状態を操作できます。

To Top