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

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

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

作成日: 更新日:

基本的な使い方

__constructメソッドは、巻き戻し機能を持たないイテレータであるNoRewindIteratorクラスの新しいインスタンスを生成するために実行されるメソッドです。このメソッドは、引数としてIteratorインターフェースを実装した既存のイテレータオブジェクトを一つ受け取ります。NoRewindIteratorは「イテレータデコレータ」と呼ばれる設計パターンの一つで、引数で受け取ったイテレータを内部的に保持し、その動作を一部変更する役割を持ちます。具体的には、foreach文などで繰り返し処理が開始される際に、通常はイテレータの内部ポインタを先頭に戻すために暗黙的に呼び出されるrewind()メソッドの実行を防ぎます。このコンストラクタによって生成されたNoRewindIteratorオブジェクトを通じて繰り返し処理を行うと、最初の巻き戻し操作がスキップされるため、イテレータが既に進行している場合でも、その現在の位置から処理を開始できます。この挙動は、一度処理を中断したイテレータを、続きから再開させたい場合などに利用されます。

構文(syntax)

1public __construct(Iterator $iterator)

引数(parameters)

Iterator $iterator

  • Iterator $iterator: ループ処理の基盤となるイテレータオブジェクト

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PHP NoRewindIterator コンストラクタで巻き戻し抑制する

1<?php
2
3// NoRewindIterator クラスのコンストラクタ (__construct) の使用例
4// このクラスは、内部のイテレータの巻き戻し操作を抑制します。
5
6// 1. まず、元となるイテレータを用意します。
7// ここでは、配列を扱うための標準イテレータである ArrayIterator を使用します。
8$data = ['Item A', 'Item B', 'Item C'];
9$originalIterator = new ArrayIterator($data);
10
11echo "--- 元のイテレータ (ArrayIterator) の内容 ---" . PHP_EOL;
12foreach ($originalIterator as $key => $value) {
13    echo "キー: {$key}, 値: {$value}" . PHP_EOL;
14}
15echo PHP_EOL;
16
17// 2. NoRewindIterator のインスタンスを作成します。
18// __construct メソッドに、先ほど作成した $originalIterator を渡します。
19// これにより、$noRewindIterator は $originalIterator を内部イテレータとして持ちます。
20$noRewindIterator = new NoRewindIterator($originalIterator);
21
22echo "--- NoRewindIterator を使った最初のイテレーション ---" . PHP_EOL;
23// NoRewindIterator を使ってデータにアクセスします。
24// 内部イテレータが順に進み、すべての要素が処理されます。
25foreach ($noRewindIterator as $key => $value) {
26    echo "処理中: {$value} (キー: {$key})" . PHP_EOL;
27}
28echo PHP_EOL;
29
30echo "--- NoRewindIterator を使った2回目のイテレーション試行 ---" . PHP_EOL;
31// NoRewindIterator は、内部イテレータの rewind() メソッドの呼び出しを無視します。
32// そのため、一度イテレーションが完了すると、内部ポインタは既に末尾に到達しているため、
33// 2回目の foreach ループでは何も処理されません。
34foreach ($noRewindIterator as $key => $value) {
35    // このブロック内のコードは実行されません
36    echo "表示されないはず: {$value}" . PHP_EOL; 
37}
38echo "(NoRewindIterator は巻き戻しを行わないため、2回目のループは何も出力しません。)" . PHP_EOL;
39
40?>

PHPのNoRewindIterator::__constructは、NoRewindIteratorクラスの新しいインスタンスを生成する際に呼び出される特別なメソッド(コンストラクタ)です。このクラスは、内部に持つイテレータ(データを順に読み出すための仕組み)の巻き戻し操作を抑制する役割を果たします。

引数としてはIterator $iteratorを一つ受け取ります。ここに、実際に反復処理を行いたい元のイテレータオブジェクトを指定します。NoRewindIteratorは、この引数で渡されたイテレータを内部で管理し、そのデータにアクセスできるようになります。コンストラクタであるため、特定の戻り値はありません。

サンプルコードでは、まずArrayIteratorを使って配列データのための基本的なイテレータを作成し、その内容を表示しています。次に、この$originalIteratorを引数としてnew NoRewindIterator()を呼び出し、NoRewindIteratorのインスタンスを生成しています。

この$noRewindIteratorを使って最初のforeachループを実行すると、元のデータが順に処理され、すべて表示されます。しかし、続けて同じ$noRewindIteratorで2回目のforeachループを試みても、何も出力されません。これは、NoRewindIteratorが内部イテレータの巻き戻し(rewind()メソッドの呼び出し)を無視するため、一度末尾に到達したポインタが先頭に戻されず、データが読み出せない状態になっているためです。この特性は、イテレータを一度だけ確実に使い切りたい場合などに役立ちます。

このサンプルコードは、NoRewindIteratorクラスのコンストラクタ__constructの基本的な使い方を示しています。__constructには、必ずIteratorインターフェースを実装したオブジェクト(例: ArrayIterator)を引数として渡す必要があります。最も重要な注意点は、NoRewindIteratorが内部イテレータの巻き戻し操作を抑制する点です。そのため、一度foreachなどでイテレーションを実行すると、内部ポインタはデータの末尾に達し、同じNoRewindIteratorインスタンスを再度ループしてもデータは処理されません。繰り返しデータを処理したい場合は、再度NoRewindIteratorのインスタンスを作成するか、元のイテレータを直接使用する必要があります。これは、データを一度だけ読み込みたい場合などに利用される特性です。

NoRewindIterator::__construct でイテレータをラップする

1<?php
2
3/**
4 * イテレータの基本的な動作を示すカスタムイテレータクラスです。
5 * NoRewindIteratorの引数として使用します。
6 */
7class MyIterator implements Iterator
8{
9    private array $items = [];
10    private int $position = 0;
11
12    /**
13     * MyIteratorのコンストラクタです。
14     * イテレータが処理するデータの配列を受け取ります。
15     *
16     * @param array $items イテレートする要素の配列。
17     */
18    public function __construct(array $items)
19    {
20        // 配列の値をコピーし、常に数値キーとなるようにします。
21        $this->items = array_values($items);
22        $this->position = 0;
23        echo "MyIterator: コンストラクタが呼ばれました。\n";
24    }
25
26    /**
27     * イテレータを最初の要素に巻き戻します。
28     * foreachループが開始される際や、再度ループする際に呼び出されます。
29     */
30    public function rewind(): void
31    {
32        echo "MyIterator: rewind() が呼ばれました (最初の位置に戻します)。\n";
33        $this->position = 0;
34    }
35
36    /**
37     * 現在の要素の値を返します。
38     *
39     * @return mixed 現在の要素の値。
40     */
41    public function current(): mixed
42    {
43        return $this->items[$this->position];
44    }
45
46    /**
47     * 現在の要素のキーを返します。
48     *
49     * @return int 現在の要素のキー。
50     */
51    public function key(): int
52    {
53        return $this->position;
54    }
55
56    /**
57     * イテレータの内部ポインタを次の要素に進めます。
58     */
59    public function next(): void
60    {
61        echo "MyIterator: next() が呼ばれました (次の要素へ進めます)。\n";
62        ++$this->position;
63    }
64
65    /**
66     * 現在のポインタ位置が有効な要素を指しているか確認します。
67     *
68     * @return bool 位置が有効な場合は true、そうでない場合は false。
69     */
70    public function valid(): bool
71    {
72        return isset($this->items[$this->position]);
73    }
74}
75
76// --- ここから NoRewindIterator::__construct の使用例 ---
77
78echo "--- NoRewindIterator::__construct の使用例を開始します ---\n\n";
79
80// 1. 基本となるイテレータ(MyIterator)を作成します。
81$data = ['Apple', 'Banana', 'Cherry'];
82$myIterator = new MyIterator($data);
83
84echo "\n--- 通常の MyIterator でのループの振る舞い ---\n";
85echo "1回目のループ:\n";
86foreach ($myIterator as $key => $value) {
87    echo "  Key: $key, Value: $value\n";
88}
89
90echo "\n2回目のループ (通常のイテレータは自動的に rewind() されます):\n";
91foreach ($myIterator as $key => $value) {
92    echo "  Key: $key, Value: $value\n";
93}
94echo "--- 通常の MyIterator でのループの振る舞い 終了 ---\n\n";
95
96
97// 2. NoRewindIterator を使用して MyIterator をラップします。
98// NoRewindIterator のコンストラクタは、引数として Iterator オブジェクトを受け取ります。
99// ここで __construct メソッドが呼び出され、内部で $myIterator を保持します。
100echo "--- NoRewindIterator を使用した MyIterator でのループの振る舞い ---\n";
101echo "NoRewindIterator のコンストラクタを呼び出し:\n";
102$noRewindIterator = new NoRewindIterator($myIterator); 
103
104echo "\n1回目のループ:\n";
105foreach ($noRewindIterator as $key => $value) {
106    echo "  Key: $key, Value: $value\n";
107}
108
109echo "\n2回目のループ (NoRewindIterator は rewind() を呼び出しません):\n";
110// NoRewindIterator は、一度消費されたイテレータを巻き戻しません。
111// そのため、2回目の foreach ループでは 'rewind()' は呼ばれず、
112// イテレータの内部ポインタは既に末尾に達しているため、要素は処理されません。
113foreach ($noRewindIterator as $key => $value) {
114    echo "  Key: $key, Value: $value\n";
115}
116echo "--- NoRewindIterator を使用した MyIterator でのループの振る舞い 終了 ---\n\n";
117
118echo "--- NoRewindIterator::__construct の使用例を終了します ---\n";
119

NoRewindIteratorクラスは、PHPでイテレータを扱う際に、通常foreachループの開始時に自動的に行われるイテレータの「巻き戻し」(ポインタを最初の要素に戻す動作)を防ぐための特殊なイテレータです。

その__constructメソッドは、NoRewindIteratorクラスの新しいインスタンスを作成する際に呼び出される初期化メソッドです。 引数としてIteratorインターフェースを実装したオブジェクト(つまり、反復処理が可能な任意のイテレータオブジェクト)を一つ受け取ります。この引数として渡されたイテレータが、NoRewindIteratorによって内部的にラップされ、実際のデータへのアクセスを担当する元のイテレータとなります。 コンストラクタは、受け取ったイテレータを内部に設定する役割を担い、特に戻り値はありません。

サンプルコードでは、まずカスタムイテレータであるMyIteratorが作成され、複数のforeachループで自動的に巻き戻されて繰り返し処理される様子が示されています。その後、このMyIteratorを引数としてNoRewindIterator::__constructメソッドに渡して新しいNoRewindIteratorインスタンスを生成しています。その結果、NoRewindIteratorを介した2回目のforeachループでは、元のイテレータのrewind()メソッドが呼び出されないため、イテレータのポインタは既に終端に達しており、要素が処理されないことが確認できます。このように、NoRewindIterator::__constructを利用することで、イテレータの巻き戻し挙動を制御することが可能になります。

NoRewindIterator::__constructは、引数にIterator型のオブジェクトを受け取り、それをラップします。このクラスの最大の注意点は、ラップされたイテレータのrewind()メソッドを抑制する点です。そのため、一度foreachなどで最後まで要素を処理したイテレータは、NoRewindIterator経由で再度ループさせても、巻き戻されることなく、すでに終端に達しているため要素を返しません。通常のイテレータはループのたびに自動的に巻き戻されるため、この挙動の違いを理解することが重要です。この特性は、一度きりのデータストリーム処理や、意図的に巻き戻しを避けたい場面で利用されます。誤って複数回ループを期待すると、意図しない結果を招く可能性があるため注意が必要です。

関連コンテンツ