【PHP8.x】IteratorIterator::__construct()メソッドの使い方
__constructメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
__constructメソッドは、既存の反復可能なオブジェクトを内包する、新しいIteratorIteratorオブジェクトのインスタンスを生成するメソッドです。このメソッドは、new IteratorIterator()のようにインスタンスが生成される際に自動的に呼び出されるコンストラクタです。主な役割は、引数として受け取ったイテレータをオブジェクトの内部に保持し、後続の処理で利用できるように初期設定を行うことです。第一引数には、Traversableインターフェースを実装したオブジェクトを指定する必要があります。Traversableとは、配列のようにforeach構文を使って要素を一つずつ順番に取り出すことができるオブジェクトの型を示します。このメソッドによって、IteratorIteratorは渡されたイテレータをラップし、その代理として振る舞うことが可能になります。これにより、元のイテレータの動作を変更することなく、統一されたインターフェースで反復処理を扱えるようになります。PHP 8.0.0からは、オプションの第二引数としてクラス名を指定でき、反復処理の各要素を指定したクラスのインスタンスとして取得する機能も提供されています。
構文(syntax)
1public __construct(Traversable $iterator)
引数(parameters)
Traversable $iterator, ?string $class = null
- Traversable $iterator: Iteratable なオブジェクトを指定します。
- ?string $class = null: IteratorIterator が使用するクラス名を指定します。指定しない場合は、デフォルトの
IteratorIteratorが使用されます。
戻り値(return)
戻り値なし
戻り値はありません
サンプルコード
PHP 8 コンストラクタプロモーションでIteratorIteratorを拡張する
1<?php 2 3/** 4 * IteratorIteratorを継承し、コンストラクタプロモーションを利用するカスタムイテレータクラス 5 * 6 * このクラスは、ラップしたイテレータの各操作でログを出力する機能を追加します。 7 */ 8class LoggableIterator extends IteratorIterator 9{ 10 /** 11 * コンストラクタ 12 * 13 * PHP 8の「コンストラクタプロモーション」機能を利用しています。 14 * `private string $logPrefix` と記述するだけで、 15 * `$logPrefix` という名前のプライベートプロパティが宣言され、 16 * コンストラクタ引数から渡された値が自動的に代入されます。 17 * これにより、プロパティ宣言とコンストラクタ内での代入文を省略でき、コードが簡潔になります。 18 * 19 * @param Traversable $iterator ラップするTraversableオブジェクト(ArrayIteratorなど) 20 * @param string $logPrefix ログ出力時に使用する接頭辞 21 */ 22 public function __construct( 23 Traversable $iterator, 24 private string $logPrefix 25 ) { 26 // 親クラスである IteratorIterator のコンストラクタを呼び出し、 27 // ラップ対象のイテレータを渡します。 28 parent::__construct($iterator); 29 } 30 31 /** 32 * イテレータを巻き戻す際にログを出力します。 33 */ 34 public function rewind(): void 35 { 36 echo "{$this->logPrefix}: イテレーションを開始します。\n"; 37 parent::rewind(); 38 } 39 40 /** 41 * 現在の要素を取得する際にログを出力します。 42 */ 43 public function current(): mixed 44 { 45 $value = parent::current(); 46 $key = parent::key(); 47 echo "{$this->logPrefix}: 要素 (キー: {$key}, 値: {$value}) を取得しました。\n"; 48 return $value; 49 } 50} 51 52// ArrayIteratorはTraversableインターフェースを実装しているため、 53// LoggableIteratorのコンストラクタに渡すことができます。 54$sourceArray = new ArrayIterator(['apple', 'banana', 'cherry']); 55 56// LoggableIteratorのインスタンスを生成します。 57// 第2引数の 'FRUITS' が、コンストラクタプロモーションによって 58// privateプロパティ $logPrefix に自動的にセットされます。 59$loggableIterator = new LoggableIterator($sourceArray, 'FRUITS'); 60 61// foreachでループさせると、オーバーライドされたメソッドが呼び出されます。 62foreach ($loggableIterator as $fruit) { 63 echo " -> ループ内の処理: '{$fruit}' を受け取りました。\n\n"; 64} 65
IteratorIteratorのコンストラクタ__constructは、新しいイテレータのインスタンスを生成する際に呼び出される特別なメソッドです。このクラスは、配列のように反復処理が可能な既存のオブジェクト(イテレータ)を内部に包み込み、それ自身もイテレータとして振る舞う機能を提供します。
第1引数$iteratorには、foreachなどでループ処理できるTraversable型のオブジェクトを指定します。サンプルコードではnew ArrayIterator()がこれにあたり、この引数で渡されたオブジェクトが処理の対象となります。
サンプルコードではIteratorIteratorを継承し、独自の機能を追加したLoggableIteratorクラスを作成しています。このコンストラクタでは、PHP 8の新機能「コンストラクタプロモーション」が活用されています。引数にprivate string $logPrefixと記述するだけで、クラス内に$logPrefixというプロパティが自動的に定義され、渡された値が代入されます。これにより、プロパティ宣言と代入の記述を省略でき、コードが簡潔になります。また、parent::__construct($iterator)を呼び出して親クラスのコンストラクタに処理を引き継ぎ、基本的な初期化を完了させています。
コンストラクタはインスタンスを初期化することが目的のため、特定の処理結果を返すことはなく、戻り値はありません。
このサンプルコードの注意点は、PHP 8で導入された「コンストラクタプロモーション」を利用している点です。コンストラクタの引数にprivateなどのアクセス修飾子を付ける書き方は、古いPHPでは構文エラーとなるため、実行環境のバージョン確認が必要です。また、IteratorIteratorのような親クラスを継承する場合、子クラスのコンストラクタ内でparent::__construct()を呼び出し、親クラスの初期化を必ず行ってください。これを忘れると、継承した機能が正しく動作せず、予期せぬエラーの原因となります。引数の型Traversableは、foreachで反復処理が可能なオブジェクトを受け取れることを示しています。
PHP 8 constructor property promotion でイテレータを拡張する
1<?php 2 3/** 4 * IteratorIteratorを継承し、追加のプロパティを持つカスタムイテレータクラス。 5 * 6 * PHP 8.0で導入された「コンストラクタプロパティプロモーション」を利用して、 7 * コンストラクタの引数でプロパティの宣言と初期化を同時に行います。 8 */ 9class DescribedIterator extends IteratorIterator 10{ 11 /** 12 * コンストラクタ 13 * 14 * public readonly string $description の部分がプロパティプロモーションです。 15 * これにより、$description プロパティの宣言と、コンストラクタ内での 16 * $this->description = $description; という代入が不要になります。 17 * 18 * @param Traversable $iterator 親クラスに渡すイテレータ 19 * @param string $description このイテレータに関する説明(プロモーションされるプロパティ) 20 */ 21 public function __construct( 22 Traversable $iterator, 23 public readonly string $description 24 ) { 25 // 必ず親クラスのコンストラクタを呼び出します。 26 parent::__construct($iterator); 27 } 28 29 /** 30 * 追加したプロパティを取得するメソッド 31 * 32 * @return string 33 */ 34 public function getDescription(): string 35 { 36 return $this->description; 37 } 38} 39 40// 処理対象のデータ配列 41$colors = ['Red', 'Green', 'Blue']; 42 43// 配列をイテレータに変換します (ArrayIteratorはTraversableです) 44$arrayIterator = new ArrayIterator($colors); 45 46// コンストラクタプロパティプロモーションを使ったクラスをインスタンス化します 47$describedIterator = new DescribedIterator($arrayIterator, 'List of primary colors'); 48 49// プロモーションで設定されたプロパティにアクセスします 50echo $describedIterator->getDescription() . PHP_EOL; 51echo '--------------------' . PHP_EOL; 52 53// IteratorIteratorを継承しているため、そのままforeachで反復処理できます 54foreach ($describedIterator as $key => $color) { 55 echo "{$key}: {$color}" . PHP_EOL; 56}
このサンプルコードは、IteratorIteratorクラスのコンストラクタを利用して、既存のイテレータに独自の機能を追加する方法を示しています。ここでは、PHP 8.0の新機能「コンストラクタプロパティプロモーション」を活用している点が特徴です。
DescribedIteratorクラスはIteratorIteratorを継承しています。このクラスのコンストラクタ__constructは2つの引数を取ります。第1引数の$iteratorは、foreachで反復処理が可能なTraversable型のオブジェクトです。この引数はparent::__construct()を通じて親クラスに渡され、イテレータとしての基本的な機能を提供します。
第2引数のpublic readonly string $descriptionが、コンストラクタプロパティプロモーションです。この記述だけで、descriptionという公開プロパティの宣言と、引数で受け取った値による初期化が同時に行われます。これにより、クラス定義がより簡潔になります。コンストラクタはインスタンスを初期化する役割を持つため、戻り値はありません。
実行部分では、配列からArrayIteratorを作成し、それを説明文と共にDescribedIteratorのコンストラクタに渡してインスタンスを生成しています。その結果、元の配列の値をforeachで処理できるだけでなく、プロパティプロモーションで設定された説明文も取得できています。
このサンプルコードで使われているコンストラクタプロパティプロモーションは、PHP 8.0以降の機能です。引数にpublicなどの可視性キーワードを付けることで、プロパティの宣言と初期化を同時に行えます。また、readonlyキーワードはPHP 8.1以降で利用でき、一度コンストラクタで値を設定すると後から変更できなくなるため、不変なデータを扱う際に安全です。IteratorIteratorのようなクラスを継承する場合、親クラスの機能を正しく引き継ぐために、コンストラクタ内でparent::__construct()を忘れずに呼び出すことが重要です。これを怠ると、イテレータとして期待通りに動作しない原因となります。