Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】InfiniteIterator::getInnerIterator()メソッドの使い方

getInnerIteratorメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

getInnerIteratorメソッドは、InfiniteIteratorオブジェクトが内部で保持している元のイテレータ(インナーイテレータ)を取得するために使用するメソッドです。InfiniteIteratorクラスは、コンストラクタで指定された別のイテレータを、その終端に達しても自動的に巻き戻し、無限に繰り返し処理できるようにするデコレータです。このgetInnerIteratorメソッドを呼び出すと、InfiniteIteratorによってラップされている、つまり飾られている元のイテレータオブジェクトそのものにアクセスすることができます。例えば、ArrayIteratorをInfiniteIteratorでラップして無限ループを実装している途中で、元の配列データを持つArrayIteratorの状態を確認したり、直接操作したりする必要が生じた場合に役立ちます。このメソッドは引数を取らず、返り値として内部に保持されているIteratorインターフェースを実装したオブジェクトを返します。これにより、InfiniteIteratorとしての無限ループの振る舞いとは別に、その基となっているイテレータを直接扱うことが可能になります。

構文(syntax)

1<?php
2
3// 元となるイテレータを作成します
4$arrayIterator = new ArrayIterator(['first', 'second', 'third']);
5
6// InfiniteIteratorで元のイテレータをラップします
7$infiniteIterator = new InfiniteIterator($arrayIterator);
8
9// getInnerIterator() を使って、ラップされている元のイテレータを取得します
10$innerIterator = $infiniteIterator->getInnerIterator();
11
12// 取得したイテレータのクラス名と、現在の要素を表示します
13var_dump(get_class($innerIterator)); // string(13) "ArrayIterator"
14var_dump($innerIterator->current());   // string(5) "first"
15
16?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

?Iterator

InfiniteIterator インスタンスが内部で保持している Iterator インスタンス、またはそれが設定されていない場合は null を返します。

サンプルコード

PHP InfiniteIterator::getInnerIterator() で内部イテレータを取得する

1<?php
2
3/**
4 * InfiniteIterator::getInnerIterator() の使用例
5 *
6 * このメソッドは、InfiniteIterator がラップしている元の(内部)イテレータを取得します。
7 * InfiniteIterator は、内部のイテレータを無限に繰り返す特性を持つイテレータです。
8 * getInnerIterator() を使用することで、その無限ループから独立して、元のイテレータにアクセスできます。
9 */
10
11// 1. ラップする元のイテレータ(内部イテレータ)を作成します。
12// ここでは ArrayIterator を使用して簡単な配列を反復処理します。
13$originalArray = ['Alpha', 'Beta', 'Gamma'];
14$innerIterator = new ArrayIterator($originalArray);
15
16echo "元のイテレータ (ArrayIterator) の内容: ";
17foreach ($innerIterator as $item) {
18    echo $item . " ";
19}
20echo PHP_EOL . PHP_EOL;
21
22// 2. 作成した ArrayIterator を InfiniteIterator でラップします。
23// これにより、元のイテレータが無限に繰り返されるようになります。
24$infiniteIterator = new InfiniteIterator($innerIterator);
25
26// 3. InfiniteIterator::getInnerIterator() を呼び出して、
27// ラップされている元のイテレータを取得します。
28$retrievedInnerIterator = $infiniteIterator->getInnerIterator();
29
30// 4. 取得したイテレータが元の ArrayIterator オブジェクトと同一であるかを確認します。
31// getInnerIterator() は元のオブジェクトの参照を返すため、=== 演算子で同一性が確認できます。
32echo "取得したイテレータは元の ArrayIterator と同じオブジェクトですか? ";
33echo ($retrievedInnerIterator === $innerIterator) ? "はい" : "いいえ";
34echo PHP_EOL . PHP_EOL;
35
36// 5. 取得した内部イテレータの現在の要素を表示します。
37// InfiniteIterator とは独立して、元のイテレータの状態を操作できます。
38// 安全のためにポインタを先頭に戻します。
39$retrievedInnerIterator->rewind();
40echo "getInnerIterator() で取得したイテレータの最初の要素: " . $retrievedInnerIterator->current() . PHP_EOL;
41
42// 補足: InfiniteIterator の動作を少しだけ確認します。
43// 無限ループを防ぐため、数回でループを中断します。
44echo "InfiniteIterator の最初の数要素: ";
45$count = 0;
46foreach ($infiniteIterator as $value) {
47    echo $value . " ";
48    $count++;
49    if ($count >= 5) {
50        break; // 無限ループになるため、強制的に終了
51    }
52}
53echo PHP_EOL;
54
55?>

PHP 8のInfiniteIteratorクラスは、他のイテレータ(内部イテレータ)を繰り返し、その要素を無限に提供する特殊なイテレータです。InfiniteIterator::getInnerIterator()メソッドは、このInfiniteIteratorが無限に繰り返している「元の」イテレータを取得するために使われます。

このメソッドは引数を取りません。戻り値は?Iterator型で、InfiniteIteratorがラップしている元のイテレータオブジェクト、または何らかの理由でイテレータがない場合にnullを返します。通常、元のイテレータは必ず存在するため、Iteratorインターフェースを実装したオブジェクトが返されます。

サンプルコードでは、まず配列を扱うArrayIteratorを作成し、これをInfiniteIteratorでラップしています。getInnerIterator()を呼び出すことで、このラップされたArrayIteratorのインスタンスを正確に取得できることを示しています。取得したイテレータは、元のオブジェクトと完全に同一であり、InfiniteIteratorの無限ループの動作とは関係なく、独立してその状態(例えば、現在の要素やポインタ位置)を操作することが可能です。これにより、無限ループの状況から離れて、元のデータの状態を確認したり、リセットしたりといった柔軟な制御が行えるようになります。

InfiniteIterator::getInnerIterator()は、InfiniteIteratorが無限に繰り返す元のイテレータオブジェクトを取得する際に使用します。このメソッドが返すのは、元のイテレータの「コピー」ではなく「参照」である点が特に重要です。そのため、取得したイテレータに対してポインタを動かすなどの操作を行うと、InfiniteIteratorが参照している元のイテレータの状態も直接変化します。これにより、予期せぬ挙動を引き起こす可能性があるため、状態変更の際は注意が必要です。また、InfiniteIterator自体をforeachで利用する際には、無限ループに陥らないよう、必ず適切な終了条件(例えばbreak文)を設定してください。本メソッドは、無限ループから独立して元のイテレータのデータや状態にアクセスしたい場合に役立ちます。

PHP InfiniteIterator の内部イテレータ取得

1<?php
2
3/**
4 * 有限の要素を生成するシンプルなジェネレータ関数です。
5 * InfiniteIteratorが内部でこのジェネレータを複数回巻き戻して再利用する様子を示します。
6 *
7 * @return Generator
8 */
9function finiteGenerator(): Generator
10{
11    // ジェネレータが開始または巻き戻されたときにメッセージを表示します。
12    echo "[ジェネレータ] 新しいシーケンスを開始/巻き戻し中..." . PHP_EOL;
13    for ($i = 1; $i <= 3; $i++) {
14        yield "Genアイテム " . $i;
15    }
16    echo "[ジェネレータ] シーケンス終了。" . PHP_EOL;
17}
18
19// 1. オリジナルのジェネレータ(イテレータ)を準備します。
20$originalGenerator = finiteGenerator();
21
22echo "--- InfiniteIterator の動作デモンストレーション ---" . PHP_EOL;
23
24// 2. InfiniteIterator を使って、この有限のジェネレータを無限にループさせます。
25// InfiniteIterator は内部のイテレータが終端に達すると、自動的に巻き戻して最初から再度イテレートします。
26$infiniteIterator = new InfiniteIterator($originalGenerator);
27
28$count = 0;
29echo "InfiniteIteratorから合計7つの要素を取り出します (ジェネレータは複数回巻き戻されます):" . PHP_EOL;
30foreach ($infiniteIterator as $item) {
31    echo "  " . $item . PHP_EOL;
32    $count++;
33    if ($count >= 7) {
34        // 無限ループにならないように、数回で break します。
35        break;
36    }
37}
38echo "--- InfiniteIterator 動作デモンストレーション終了 ---" . PHP_EOL . PHP_EOL;
39
40
41echo "--- InfiniteIterator::getInnerIterator() の動作デモンストレーション ---" . PHP_EOL;
42
43// 3. getInnerIterator() を使用して、InfiniteIterator に渡した元のイテレータ(ジェネレータ)を取得します。
44// このメソッドの戻り値の型は `?Iterator` (PHP 8) ですが、
45// InfiniteIterator のコンストラクタは `Iterator` 型を要求するため、
46// ここでは常に `Iterator` インスタンスが返されます。
47$retrievedIterator = $infiniteIterator->getInnerIterator();
48
49// 4. 取得したイテレータが元のイテレータと同一インスタンスであることを確認します。
50echo "元のジェネレータのクラス: " . get_class($originalGenerator) . PHP_EOL;
51echo "取得したイテレータのクラス: " . get_class($retrievedIterator) . PHP_EOL;
52
53if ($originalGenerator === $retrievedIterator) {
54    echo "=> 取得したイテレータは、元のジェネレータと完全に同一のインスタンスです。" . PHP_EOL;
55} else {
56    // 通常、InfiniteIteratorに対してこの状況は発生しません。
57    echo "=> 取得したイテレータは、元のジェネレータと異なるインスタンスです。" . PHP_EOL;
58}
59
60// 取得したイテレータの状態を確認します。
61// InfiniteIteratorがすでに元のジェネレータを複数回消費していますが、
62// getInnerIterator()で取得されたイテレータは再度イテレート可能です。
63// InfiniteIteratorが内部で rewind() を呼び出すため、再度最初の状態に戻ります。
64echo "取得したイテレータを再度イテレートしてみます (巻き戻されて最初の状態に戻ります):" . PHP_EOL;
65foreach ($retrievedIterator as $item) {
66    echo "  (取得) " . $item . PHP_EOL;
67}
68echo "--- getInnerIterator() 動作デモンストレーション終了 ---" . PHP_EOL;

PHPのInfiniteIteratorクラスは、有限の要素を持つイテレータ(今回の例ではジェネレータ)を、終端に達しても自動的に巻き戻して繰り返し利用することで、まるで無限に続くかのように扱うことができる特殊なイテレータです。

InfiniteIterator::getInnerIterator()メソッドは、このInfiniteIteratorオブジェクトが内部で保持し、繰り返し利用している「元のイテレータ」を取得するために使用されます。このメソッドは引数を必要としません。戻り値の型はPHP 8では?Iterator(Iterator型またはnull)と定義されていますが、InfiniteIteratorのコンストラクタは必ずIterator型のインスタンスを受け取るため、このメソッドは常にIteratorのインスタンスを返します。

サンプルコードでは、まずfiniteGeneratorというジェネレータ関数で有限の要素を生成し、これをInfiniteIteratorに渡しています。InfiniteIteratorは、ジェネレータの要素を消費し尽くすと、自動的にそのジェネレータを巻き戻して再度利用することで、無限ループのように要素を提供します。その後、getInnerIterator()を呼び出すと、InfiniteIteratorが内部で利用していた元のfiniteGeneratorのインスタンスが取得されます。この取得されたイテレータは、元のジェネレータと全く同じインスタンスであり、InfiniteIteratorによって巻き戻された状態(最初の要素を指す状態)に戻っているため、再び最初からイテレートできることを確認できます。このメソッドにより、ラップされた元のイテレータに直接アクセスし、その状態の確認や再利用が可能になります。

InfiniteIterator::getInnerIterator()の利用に関する注意点です。

まず、InfiniteIteratorは内部のイテレータを無限に繰り返すため、サンプルコードのように必ずbreakなどの終了条件を設定しないと、意図しない無限ループが発生する可能性があります。

getInnerIterator()メソッドは、InfiniteIteratorのコンストラクタに渡した元のイテレータ(ジェネレータ)と全く同じインスタンスを返します。コピーではないため、取得したイテレータに対する操作は元のイテレータに直接影響します。

また、取得したイテレータは、InfiniteIteratorが内部でrewind()を呼び出すため、常に最初の状態にリセットされた状態で提供されます。これにより、InfiniteIteratorがどれだけイテレートを進めていても、getInnerIterator()で取得したイテレータはいつでも最初から再利用可能です。

PHP 8以降で戻り値の型が?Iterator(null許容)とされていますが、InfiniteIteratorのコンストラクタはIteratorインスタンスを必須とするため、このメソッドがnullを返すことは通常ありません。常に有効なIteratorインスタンスが返されると理解してください。

関連コンテンツ

関連プログラミング言語