【PHP8.x】OuterIterator::rewind()メソッドの使い方
rewindメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
rewindメソッドは、PHPのOuterIteratorクラスに属し、現在参照している要素の位置をコレクションの先頭に戻す処理を実行するメソッドです。
OuterIteratorクラスは、別のイテレータ(内部イテレータ)をラップし、そのイテレータが提供するデータ群に対して反復処理を行うための機能を提供します。このrewindメソッドが呼び出されると、OuterIteratorは自身がラップしている内部イテレータに対しても、その現在位置を先頭に戻すよう指示します。これにより、データ群を最初から繰り返し処理したい場合や、ループ処理を開始する前に、イテレータのポインタが常に正しい開始位置にリセットされることが保証されます。
例えば、foreachループを使用してOuterIteratorを走査する際、ループの開始時に自動的にこのrewindメソッドが呼び出され、データ群の先頭から処理が開始されるようになります。明示的にこのメソッドを呼び出すことで、複数のループで同じデータ群を最初から再利用することも可能となり、データ構造の反復処理において、イテレータの現在の位置を初期化する非常に重要な役割を持つメソッドです。
構文(syntax)
1<?php 2 3/** @var OuterIterator $outerIterator */ 4$outerIterator->rewind();
引数(parameters)
引数なし
引数はありません
戻り値(return)
戻り値なし
戻り値はありません
サンプルコード
PHP ジェネレータを複数回イテレートする
1<?php 2 3/** 4 * ジェネレータを複数回繰り返し処理できるようにラップするイテレータ。 5 * 6 * PHPの標準ジェネレータは一度しかイテレートできませんが、このクラスは 7 * rewind() メソッドが呼ばれるたびに新しいジェネレータインスタンスを作成することで、 8 * 複数回にわたるイテレーション(繰り返し処理)を可能にします。 9 */ 10class RewindableGenerator implements Iterator 11{ 12 /** 13 * @var callable ジェネレータを生成するファクトリ関数(引数なしでGeneratorを返すクロージャなど)。 14 */ 15 private $generatorFactory; 16 17 /** 18 * @var Generator|null 現在のジェネレータインスタンス。 19 */ 20 private ?Generator $currentGenerator = null; 21 22 /** 23 * コンストラクタ。ジェネレータを生成するファクトリ関数を受け取ります。 24 * 25 * @param callable $generatorFactory 引数なしでGeneratorを返すcallable。 26 */ 27 public function __construct(callable $generatorFactory) 28 { 29 $this->generatorFactory = $generatorFactory; 30 } 31 32 /** 33 * イテレータを最初の要素に巻き戻します。 34 * このメソッドが呼ばれるたびに、新しいジェネレータインスタンスが作成されます。 35 * これにより、以前に消費されたジェネレータでも最初から再度処理を開始できます。 36 */ 37 public function rewind(): void 38 { 39 // ジェネレータファクトリを呼び出し、新しいジェネレータインスタンスを作成 40 $this->currentGenerator = ($this->generatorFactory)(); 41 } 42 43 /** 44 * 現在の要素を返します。 45 * 46 * @return mixed 現在のイテレーションの要素。 47 */ 48 public function current(): mixed 49 { 50 return $this->currentGenerator?->current(); 51 } 52 53 /** 54 * 現在の要素のキーを返します。 55 * 56 * @return mixed 現在のイテレーションのキー。 57 */ 58 public function key(): mixed 59 { 60 return $this->currentGenerator?->key(); 61 } 62 63 /** 64 * 次の要素に進みます。 65 */ 66 public function next(): void 67 { 68 $this->currentGenerator?->next(); 69 } 70 71 /** 72 * 現在の要素が有効か (イテレーションが終了していないか) を確認します。 73 * 74 * @return bool 有効な場合はtrue、そうでない場合はfalse。 75 */ 76 public function valid(): bool 77 { 78 return $this->currentGenerator?->valid() ?? false; 79 } 80} 81 82/** 83 * サンプルとして使用するジェネレータ関数。 84 * 動作を分かりやすくするため、開始と終了、各yieldでメッセージを表示します。 85 * 86 * @return Generator 87 */ 88function exampleGenerator(): Generator 89{ 90 echo " >> Generator started.\n"; 91 for ($i = 1; $i <= 3; $i++) { 92 yield "Item " . $i; 93 echo " >> Yielded Item " . $i . ".\n"; 94 } 95 echo " >> Generator ended.\n"; 96} 97 98echo "--- 最初のイテレーション ---\n"; 99// RewindableGenerator のインスタンスを作成 100// ジェネレータを生成するクロージャ(ファクトリ関数)を渡します。 101$rewindableGen = new RewindableGenerator(function () { 102 return exampleGenerator(); 103}); 104 105// 最初の foreach ループ。ループ開始時に RewindableGenerator::rewind() が自動的に呼ばれます。 106foreach ($rewindableGen as $key => $value) { 107 echo " Received: [{$key}] {$value}\n"; 108} 109 110echo "\n--- 2回目のイテレーション (自動巻き戻し) ---\n"; 111// 2回目の foreach ループ。ここでも RewindableGenerator::rewind() が自動的に呼ばれ、 112// 新しいジェネレータが生成されるため、最初から処理が再開されます。 113foreach ($rewindableGen as $key => $value) { 114 echo " Received: [{$key}] {$value}\n"; 115} 116 117echo "\n--- 3回目のイテレーション (明示的な巻き戻し) ---\n"; 118// foreach ループの前に RewindableGenerator::rewind() を明示的に呼び出す例。 119// これも新しいジェネレータを生成し、処理を最初から開始させます。 120$rewindableGen->rewind(); 121echo " 明示的に rewind() を呼び出しました。\n"; 122foreach ($rewindableGen as $key => $value) { 123 echo " Received: [{$key}] {$value}\n"; 124} 125 126echo "\n--- サンプル終了 ---\n";
PHPのRewindableGeneratorクラスにおけるrewind()メソッドは、イテレータの処理を一番最初の要素からやり直すために使用されます。通常のPHPジェネレータは一度しか最後まで処理できませんが、このRewindableGeneratorクラスは、ジェネレータを複数回繰り返し利用できるようにするためのものです。
このrewind()メソッドは引数を一切取らず、戻り値もありません。メソッドが呼び出されるたびに、内部的に新しいジェネレータインスタンスが作成されます。これにより、すでに一度最後まで処理されたジェネレータであっても、rewind()を呼び出すことで、再度データの最初から処理を開始できるようになります。
例えば、foreachループでRewindableGeneratorのインスタンスを使用する場合、ループが始まる前にrewind()が自動的に実行されます。そのため、同じインスタンスを複数のforeachループで使う際にも、各ループで新しいジェネレータが用意され、常にデータの最初から繰り返し処理が行われるのです。また、$rewindableGen->rewind()のように明示的に呼び出すことも可能で、その場合も新しいジェネレータが生成され、最初からの処理が再開されます。
このサンプルコードは、標準のPHPジェネレータが一度しかイテレートできない問題を解決し、複数回繰り返し処理を可能にする方法を示しています。特にrewind()メソッドは、イテレータを最初の状態に戻す役割を果たし、このクラスでは呼ばれるたびに新しいジェネレータインスタンスを生成しています。初心者の方は、foreachループが内部で自動的にrewind()を呼び出すため、意識せずに処理が最初から再開される点を理解しておくと良いでしょう。ジェネレータの生成処理にコストがかかる場合、rewind()が頻繁に呼ばれるとパフォーマンスに影響が出る可能性があるため注意が必要です。また、ジェネレータが外部の状態に依存する場合は、巻き戻し時の挙動をよく確認してください。
PHP OuterIterator rewindで配列を巻き戻す
1<?php 2 3/** 4 * OuterIterator インターフェースを実装するカスタムイテレータ。 5 * 配列をラップした ArrayIterator を内包し、そのイテレーション機能を提供します。 6 * 7 * OuterIterator は Iterator インターフェースを継承するため、 8 * current(), key(), next(), rewind(), valid() の全メソッドを実装する必要があります。 9 */ 10class MyArrayOuterIterator implements OuterIterator 11{ 12 /** @var Iterator 内部でラップされるイテレータ */ 13 private Iterator $innerIterator; 14 15 /** 16 * コンストラクタ。 17 * 渡された配列を元に ArrayIterator を初期化し、内部イテレータとして設定します。 18 * 19 * @param array $array イテレーションする配列 20 */ 21 public function __construct(array $array) 22 { 23 $this->innerIterator = new ArrayIterator($array); 24 } 25 26 /** 27 * 内部でラップしているイテレータを返します。 28 * OuterIterator インターフェースの要件です。 29 * 30 * @return Iterator|null 内部イテレータ、または存在しない場合は null 31 */ 32 public function getInnerIterator(): ?Iterator 33 { 34 return $this->innerIterator; 35 } 36 37 /** 38 * 現在の要素の値を返します。 39 * Iterator インターフェースの要件です。 40 * 41 * @return mixed 現在の要素の値 42 */ 43 public function current(): mixed 44 { 45 return $this->innerIterator->current(); 46 } 47 48 /** 49 * 現在の要素のキーを返します。 50 * Iterator インターフェースの要件です。 51 * 52 * @return mixed 現在の要素のキー 53 */ 54 public function key(): mixed 55 { 56 return $this->innerIterator->key(); 57 } 58 59 /** 60 * イテレータを次の要素に進めます。 61 * Iterator インターフェースの要件です。 62 */ 63 public function next(): void 64 { 65 $this->innerIterator->next(); 66 } 67 68 /** 69 * イテレータを最初の要素に巻き戻します。 70 * Iterator インターフェースの要件です。 71 * 72 * これにより、一度イテレーションが完了した後でも、 73 * 再度最初からイテレーションを開始できるようになります。 74 */ 75 public function rewind(): void 76 { 77 echo "--> イテレータを最初の要素に巻き戻しています。\n"; 78 $this->innerIterator->rewind(); 79 } 80 81 /** 82 * 現在の位置が有効かどうか(イテレーションを続行できるか)をチェックします。 83 * Iterator インターフェースの要件です。 84 * 85 * @return bool 有効な場合は true、それ以外は false 86 */ 87 public function valid(): bool 88 { 89 return $this->innerIterator->valid(); 90 } 91} 92 93// ----------------------------------------------------------------------------- 94// サンプルコードの実行部分 95// ----------------------------------------------------------------------------- 96 97// イテレーションする配列データ 98$data = ['apple', 'banana', 'cherry', 'date']; 99 100// MyArrayOuterIterator のインスタンスを作成 101$iterator = new MyArrayOuterIterator($data); 102 103echo "最初のイテレーション:\n"; 104// foreach ループは、内部的に rewind() を呼び出してからイテレーションを開始します。 105foreach ($iterator as $key => $value) { 106 echo " Key: {$key}, Value: {$value}\n"; 107} 108 109echo "\n最初のイテレーション完了。\n"; 110 111// イテレータが終端に達しているため、このままでは再度イテレーションできません。 112// rewind() メソッドを明示的に呼び出して、イテレータをリセットします。 113$iterator->rewind(); 114 115echo "\n二度目のイテレーション(rewind() 呼び出し後):\n"; 116// rewind() によってイテレータがリセットされたため、再度最初からイテレーションが可能です。 117foreach ($iterator as $key => $value) { 118 echo " Key: {$key}, Value: {$value}\n"; 119} 120 121echo "\n二度目のイテレーション完了。\n"; 122 123?>
PHPのOuterIterator::rewindメソッドは、イテレータの現在位置をコレクションの最初の要素に戻すための機能です。このメソッドは、実際にはIteratorインターフェースで定義されている必須メソッドの一つであり、OuterIteratorインターフェースを実装するクラスもこのrewindメソッドを実装する必要があります。引数はなく、何も値を返しません(void)。
サンプルコードでは、MyArrayOuterIteratorクラスが配列をラップしたArrayIteratorを内部に持ち、そのrewindメソッドを呼び出すことで、イテレータの状態をリセットし、最初の要素を指すようにしています。
通常、foreachループでイテレータを使用する際、ループ開始時に内部的にrewindが自動的に呼び出されます。そのため、最初のforeachループでは意識せずとも最初から要素を処理できます。一度イテレーションが完了し、イテレータが終端に達した後に、再度最初から要素を処理したい場合、明示的に$iterator->rewind()を呼び出す必要があります。これにより、イテレータが「巻き戻され」、二度目のforeachループでも最初からすべての要素にアクセスできるようになります。これは、配列データなどを複数回走査する際に役立ちます。
rewind()はイテレータを最初の状態にリセットするメソッドです。foreachループは通常、イテレーション開始時に自動でrewind()を呼び出すため、多くの場合は明示的な呼び出しは不要です。しかし、一度イテレーションを完了したイテレータを再度最初から使いたい場合は、必ずrewind()を明示的に呼び出す必要があります。これを忘れると、イテレータは終端のままであり、二度目のforeachは何も処理しません。このメソッドは引数を取らず、戻り値もありませんので、メソッドチェーンなどには利用できません。