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

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

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

作成日: 更新日:

基本的な使い方

『rewindメソッドは、ParentIteratorが内包する親イテレータを、その最初の要素に巻き戻す処理を実行するメソッドです』 ParentIteratorは、再帰的なイテレータを扱うRecursiveIteratorIteratorと組み合わせて使用され、現在の要素の親イテレータにアクセスする機能を提供します。このrewindメソッドは、その親イテレータの内部ポインタを先頭に戻す役割を担います。具体的には、ParentIteratorが保持している内部イテレータオブジェクト自身のrewindメソッドを呼び出します。この操作は、Iteratorインターフェースを実装するクラスにおける標準的な動作であり、foreachループのような反復処理が開始される際に、PHPエンジンによって内部的に自動で呼び出されます。これにより、ループが常にイテレータの先頭から開始されることが保証されます。開発者がこのメソッドを直接呼び出すことは少ないですが、イテレータの動作原理を理解する上で重要なメソッドです。なお、このメソッドは値を返しません。

構文(syntax)

1<?php
2
3$fruits = [
4    'citrus' => ['orange', 'lemon'],
5    'berries' => ['strawberry', 'raspberry'],
6];
7
8$iterator = new ParentIterator(new RecursiveArrayIterator($fruits));
9
10// イテレータを一度最後まで進める
11foreach ($iterator as $key => $value) {
12    // 何らかの処理
13}
14
15// rewind() を呼び出して、イテレータを先頭に戻す
16$iterator->rewind();
17
18// valid() は true を返し、current() は最初の要素を返す
19if ($iterator->valid()) {
20    echo $iterator->key(); // "citrus"
21}

引数(parameters)

引数なし

引数はありません

戻り値(return)

void

このメソッドは、イテレータを最初の要素に戻すために使用されます。戻り値はありません。

サンプルコード

PHPジェネレータの巻き戻しを可能にするクラス

1<?php
2
3declare(strict_types=1);
4
5/**
6 * PHPのジェネレータは通常、一度しかイテレートできません(巻き戻し不可)。
7 * このクラスは Iterator インターフェースを実装し、ジェネレータをラップすることで、
8 * rewind() が呼ばれるたびに新しいジェネレータを生成し、巻き戻しを可能にします。
9 *
10 * @template TKey
11 * @template TValue
12 * @implements Iterator<TKey, TValue>
13 */
14class RewindableGenerator implements Iterator
15{
16    /**
17     * ジェネレータを生成するためのファクトリ関数(クロージャ)。
18     *
19     * @var Closure(): Generator<TKey, TValue>
20     */
21    private readonly Closure $generatorFactory;
22
23    /**
24     * 現在のイテレーションで使われているジェネレータインスタンス。
25     * rewind() のたびに再生成されます。
26     *
27     * @var null|Generator<TKey, TValue>
28     */
29    private ?Generator $iterator = null;
30
31    /**
32     * コンストラクタ。
33     *
34     * @param callable(): Generator<TKey, TValue> $generatorFactory ジェネレータを返す関数
35     */
36    public function __construct(callable $generatorFactory)
37    {
38        // 受け取った callable をクロージャとして保持します。
39        $this->generatorFactory = $generatorFactory(...);
40    }
41
42    /**
43     * イテレータを先頭に巻き戻します。
44     * 内部でファクトリ関数を呼び出し、新しいジェネレータインスタンスを生成します。
45     * foreach ループの開始時に自動的に呼び出されます。
46     */
47    public function rewind(): void
48    {
49        $this->iterator = ($this->generatorFactory)();
50    }
51
52    /**
53     * 現在の要素が有効かどうかを返します。
54     */
55    public function valid(): bool
56    {
57        // Iterator の規約により、rewind() が事前に呼ばれていることが前提です。
58        return $this->iterator->valid();
59    }
60
61    /**
62     * 現在の要素のキーを返します。
63     */
64    public function key(): mixed
65    {
66        return $this->iterator->key();
67    }
68
69    /**
70     * 現在の要素の値を返します。
71     */
72    public function current(): mixed
73    {
74        return $this->iterator->current();
75    }
76
77    /**
78     * イテレータを次の要素に進めます。
79     */
80    public function next(): void
81    {
82        $this->iterator->next();
83    }
84}
85
86// ---- 以下、サンプルコードの実行部分 ----
87
88/**
89 * 1から3までの数値を生成するジェネレータ関数です。
90 * 実行されるたびにメッセージを出力し、いつ再生成されたかを確認できるようにします。
91 */
92function createNumberGenerator(): Generator
93{
94    echo "--- ジェネレータが開始されました ---\n";
95    for ($i = 1; $i <= 3; $i++) {
96        // yieldキーワードで値を一つずつ生成します。
97        yield $i;
98    }
99    echo "--- ジェネレータが終了しました ---\n";
100}
101
102// 作成したクラスを使って、巻き戻し可能なジェネレータのインスタンスを生成します。
103$rewindable = new RewindableGenerator('createNumberGenerator');
104
105// 1回目のループ: foreachは最初にrewind()を呼び出し、ジェネレータが生成されます。
106echo "[1回目] イテレーションを開始します。\n";
107foreach ($rewindable as $number) {
108    echo "数値: {$number}\n";
109}
110echo "\n";
111
112// 2回目のループ: 再びforeachが開始されると、もう一度rewind()が呼び出されます。
113// これによりジェネレータが再生成され、先頭からイテレーションが始まります。
114echo "[2回目] イテレーションを開始します。(巻き戻しが機能しているか確認)\n";
115foreach ($rewindable as $number) {
116    echo "数値: {$number}\n";
117}

rewind()メソッドは、イテレータを最初の要素に巻き戻すためのメソッドです。foreachのようなループ処理でコレクションを扱う際に、ループの開始時に自動的に呼び出されます。このメソッドは引数を取らず、戻り値もありません(void)。その役割は、イテレータの内部的な位置を先頭に戻すことにあります。

PHPの標準的なジェネレータは、一度最後まで処理を進めると巻き戻すことができず、再度利用することはできません。サンプルコードのRewindableGeneratorクラスは、この制約を解決するためのものです。

このクラスのrewind()メソッドは、内部でジェネレータを生成するための関数(ファクトリ)を呼び出します。これにより、rewind()が実行されるたびに全く新しいジェネレータインスタンスが生成され、イテレータが初期化されます。

サンプルコードではforeachループを2回実行しています。2回目のループが開始される際にもrewind()が呼び出され、ジェネレータが再生成されるため、再び1から3までの数値が出力されます。このようにして、本来は一度しか使えないジェネレータを何度も繰り返し利用可能にしています。

PHPのジェネレータは、通常一度しか繰り返し処理ができない「使い捨て」の仕組みです。このコードは、Iteratorインターフェースを実装することで、ジェネレータを複数回利用可能にしています。foreachループが開始される際、必ず最初にrewind()メソッドが自動で呼び出されます。この仕組みを利用し、rewind()メソッド内でジェネレータを生成する関数を再実行することで、常に新しいジェネレータを作り直しています。これにより、2回目以降のforeachでも先頭から処理が開始され、巻き戻しを実現しています。注意点として、ループのたびに生成処理がゼロから実行されるため、データベース接続のようなコストの高い処理をジェネレータ生成に含めると、パフォーマンスに影響が出る可能性があります。

ParentIterator::rewind() でイテレータを巻き戻す

1<?php
2
3/**
4 * ParentIterator::rewind() の動作を示すサンプルクラスです。
5 *
6 * イテレータを先頭に巻き戻す rewind() メソッドの挙動を確認します。
7 * foreach ループの開始時に暗黙的に呼び出されるほか、
8 * 明示的に呼び出すことで再度イテレータを先頭から利用できます。
9 */
10class ParentIteratorRewindExample
11{
12    /**
13     * サンプルを実行します。
14     */
15    public function run(): void
16    {
17        // 親を持つ再帰的なデータ構造(多次元配列)を準備します。
18        $data = [
19            'fruits' => ['apple', 'banana', 'cherry'],
20            'vegetables' => ['carrot', 'potato', 'spinach'],
21        ];
22
23        // 多次元配列を走査するための再帰イテレータを作成します。
24        $recursiveIterator = new RecursiveArrayIterator($data);
25
26        // 再帰イテレータをラップし、親要素のみを走査する ParentIterator を作成します。
27        // ParentIterator は、子を持つ要素 (この例では 'fruits' と 'vegetables') を対象とします。
28        $parentIterator = new ParentIterator($recursiveIterator);
29
30        echo "1回目のループを開始します。\n";
31        // foreach ループが始まる際、内部的に ParentIterator::rewind() が呼び出されます。
32        foreach ($parentIterator as $key => $value) {
33            // key() メソッドで親要素のキーを取得できます。
34            echo "親のキー: " . $parentIterator->key() . "\n";
35        }
36        echo "1回目のループが終了しました。\n\n";
37
38        echo "rewind() を明示的に呼び出して、イテレータを先頭に戻します。\n";
39        // イテレータを手動で先頭に巻き戻します。
40        $parentIterator->rewind();
41
42        echo "2回目のループを開始します。\n";
43        // rewind() されたため、再び先頭から要素を走査できます。
44        foreach ($parentIterator as $key => $value) {
45            echo "親のキー: " . $parentIterator->key() . "\n";
46        }
47        echo "2回目のループが終了しました。\n";
48    }
49}
50
51// サンプルコードの実行
52$example = new ParentIteratorRewindExample();
53$example->run();
54

PHPのParentIterator::rewind()は、イテレータを最初の位置に巻き戻すためのメソッドです。このメソッドは、foreachループが開始される際にPHPによって自動的に呼び出され、イテレーションが必ず先頭の要素から始まることを保証します。

サンプルコードでは、まず多次元配列から親要素のみを走査するParentIteratorを作成しています。1回目のforeachループでは、内部的にrewind()が実行され、「fruits」と「vegetables」という2つの親キーが順番に出力されます。

ループが終了した後、$parentIterator->rewind()を明示的に呼び出しています。これにより、一度終端まで進んだイテレータの内部ポインタが再び先頭に戻ります。そのため、2回目のforeachループを実行すると、再度同じ要素が先頭から順番に処理され、1回目と同じ結果が出力されることが確認できます。このように、rewind()を使うことで、同じイテレータを繰り返し先頭から利用することが可能になります。

このメソッドは引数を必要とせず、処理の成功・失敗などを示す戻り値もありません(void)。

ParentIterator::rewind()は、イテレータを最初の要素に戻すためのメソッドです。foreachループが始まる際には、PHPによって内部的に自動で呼び出されるため、通常は開発者が意識する必要はありません。一度foreachループで最後まで処理したイテレータを、もう一度最初から使いたい場合にのみ、明示的にrewind()を呼び出します。サンプルコードのようにrewind()を呼び出さずに2回目のループを実行しようとすると、イテレータが終端に達したままなので何も処理されません。また、ParentIteratorは再帰的な構造の中で、子要素を持つ要素のみを走査対象とすることにも注意してください。

関連コンテンツ