PHPジェネレーターとイテレーターオブジェクトの仕組みを解説
はじめに
PHPでは、ジェネレーター関数を呼び出すと、内部的にGeneratorクラスの新しいオブジェクトが返されます。このオブジェクトはIteratorインターフェイスを実装しているため、通常のイテレーターと同じように扱うことができます。
Iteratorインターフェイスには、次の抽象メソッドが定義されています。
- Iterator::current() — 現在の要素を返す
- Iterator::key() — 現在の要素のキーを返す
- Iterator::next() — 次の要素へ進む
- Iterator::rewind() — イテレーターを先頭の要素まで巻き戻す
- Iterator::valid() — 現在位置が有効かどうかを判定する
Generatorは前方移動専用(forward-only)のイテレーターとして動作します。さらに、ジェネレーターの状態を操作するための各種メソッドも提供されており、値の送信や取得などを行うことも可能です。
ジェネレーターをイテレーターとして使う
次の例では、ジェネレーター関数がファイルの内容を1行ずつyieldで返し、生成されたジェネレーターオブジェクトをforeachループで走査しています。current()やnext()といったイテレーターのメソッドも直接呼び出せます。
ただし、ジェネレーターは前方移動専用のイテレーターであるため、一度走査した後にrewind()メソッドを呼び出すと例外がスローされる点に注意してください。
コード例
<?php
function filegenerator($name) {
$fileHandle = fopen($name, 'r');
while ($line = fgets($fileHandle)) {
yield $line;
}
fclose($fileHandle);
}
$name = "test.txt";
$file = filegenerator($name);
// foreachループで全行を走査
foreach ($file as $line)
echo $line;
// すでに走査済みのジェネレーターを巻き戻そうとする
$file->rewind();
echo $file->current();
$file->next();
echo $file->current();
?>実行結果
ファイルの行をすべて走査した後でrewind()を呼び出すと、以下のような致命的エラー(fatal error)が発生します。
PHP User Defined Functions PHP Function Arguments PHP Variable Functions PHP Internal (Built-in) Functions PHP Anonymous functions PHP Arrow Functions PHP Fatal error: Uncaught Exception: Cannot rewind a generator that was already run
このエラーメッセージは「すでに実行が完了したジェネレーターは巻き戻せない」ことを示しています。ジェネレーターを使用する際は、前方移動のみが可能であるという特性を理解した上で設計することが重要です。
-
PHPで匿名クラスを使ってオブジェクトを作成する方法
PHP 7以降では、名前を持たない「匿名クラス(無名クラス)」を作成できるようになりました。PHPではすべてのオブジェクトが何らかのクラスと関連付けられていますが、匿名クラスも通常のクラスと同様にインスタンス化してオブジェクトを生成することが可能です。匿名クラスの基本構文匿名クラスは new class という構文で定義します。クラス名を宣言することなく、その場でオブジェクトを生成できるのが大きな特徴です。他のクラスと同じように、extends を使って既存のクラスを継承することもできます。サンプルコード<?php class my_sample_class {}
-
Pythonジェネレーター徹底解説:yieldの基本からメモリ効率化テクニックまで
Pythonにおけるジェネレーターは、PEP 255で導入されて以来、言語の中核を担う重要な機能の一つとなっています。本記事では、ジェネレーターの基本的な概念から、実際のコード例、そして大規模データ処理におけるメモリ効率化の実践テクニックまで、詳しく解説します。 ジェネレーターとは何か ジェネレーターとは、ループの反復動作を制御するための特別なルーチンです。配列を返す関数に似ていますが、決定的な違いがあります。通常の関数が配列全体を一度に返すのに対し、ジェネレーターは値を1つずつ生成(yield)します。これにより、必要なメモリ量を大幅に抑えることができます。 「yield」キーワードを含