【PHP8.x】RecursiveIteratorIterator::__construct()メソッドの使い方
__constructメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
__constructメソッドは、RecursiveIteratorIteratorの新しいインスタンスを生成するメソッドです。このメソッドは、多次元配列や木構造のような階層的なデータ構造を再帰的に走査するための準備を行います。最初の引数には、走査対象となるRecursiveIteratorインターフェースを実装したオブジェクトを指定します。これにより、入れ子になったデータ構造を反復処理の対象として設定します。2番目の引数では、反復処理の挙動を制御するモードを指定します。例えば、デフォルトのモードであるLEAVES_ONLYは、子を持たない末端の要素のみを返します。SELF_FIRSTモードを指定すると、親要素を処理した後にその子要素を処理し、CHILD_FIRSTモードでは逆に子要素をすべて処理した後に親要素を処理します。このように、コンストラクタで走査対象と挙動モードを初期設定することで、複雑なデータ構造を単純なループで効率的に扱うことが可能になります。
構文(syntax)
1<?php 2$traversableObject = new RecursiveArrayIterator(['a', ['b', 'c']]); 3 4$instance = new RecursiveIteratorIterator( 5 $traversableObject, // 第1引数: Traversableなイテレータ 6 RecursiveIteratorIterator::LEAVES_ONLY, // 第2引数(オプション): モード 7 0 // 第3引数(オプション): フラグ 8);
引数(parameters)
Traversable $iterator, int $mode = RecursiveIteratorIterator::LEAVES_ONLY, int $flags = 0
- Traversable $iterator: 再帰的にイテレーションを行う対象の Traversable オブジェクト
- int $mode = RecursiveIteratorIterator::LEAVES_ONLY: イテレーションのモードを指定する整数。デフォルトは葉ノードのみを処理するモード
- int $flags = 0: イテレーションの追加フラグを指定する整数
戻り値(return)
戻り値なし
戻り値はありません
サンプルコード
PHP 8: コンストラクタ昇格と再帰イテレータを学ぶ
1<?php 2 3/** 4 * RecursiveIteratorIterator とコンストラクタのプロパティ昇格を学ぶためのクラス 5 * 6 * このクラスは、内部で RecursiveIteratorIterator を利用して、 7 * 再帰的なデータ構造を走査します。 8 */ 9class MyRecursiveTreeWalker 10{ 11 // RecursiveIteratorIterator のインスタンスを保持するプロパティ 12 private RecursiveIteratorIterator $iteratorIterator; 13 14 /** 15 * コンストラクタ 16 * 17 * PHP 8.0 の "コンストラクタのプロパティ昇格 (Constructor Property Promotion)" を使用しています。 18 * 引数にアクセス修飾子 (例: private) を付けることで、プロパティの宣言と 19 * コンストラクタ内での代入 ($this->iterator = $iterator;) を同時に行い、コードを簡潔にします。 20 * 21 * @param Traversable $iterator 再帰的に処理するイテレータ (例: RecursiveArrayIterator) 22 * @param int $mode イテレータの振る舞いを決めるモード (デフォルトは葉、つまり末端の要素のみ) 23 * @param int $flags 追加のフラグ (デフォルトはなし) 24 */ 25 public function __construct( 26 private Traversable $iterator, 27 private int $mode = RecursiveIteratorIterator::LEAVES_ONLY, 28 private int $flags = 0 29 ) { 30 // プロパティ昇格で受け取った引数を使い、RecursiveIteratorIterator のインスタンスを生成します。 31 $this->iteratorIterator = new RecursiveIteratorIterator( 32 $this->iterator, 33 $this->mode, 34 $this->flags 35 ); 36 } 37 38 /** 39 * イテレータの内容を再帰的に表示します。 40 */ 41 public function displayLeafNodes(): void 42 { 43 echo "--- Tree Leaves ---" . PHP_EOL; 44 foreach ($this->iteratorIterator as $key => $value) { 45 // $mode が LEAVES_ONLY なので、末端の要素のみが出力されます。 46 echo "{$key}: {$value}" . PHP_EOL; 47 } 48 } 49} 50 51// サンプル用の多次元配列データ 52$data = [ 53 'name' => 'Taro Yamada', 54 'skills' => [ 55 'PHP', 56 'JavaScript', 57 ], 58 'projects' => [ 59 'Project A' => ['status' => 'completed'], 60 'Project B' => ['status' => 'in-progress'], 61 ], 62]; 63 64// 多次元配列をイテレートするための RecursiveArrayIterator を作成します。 65$arrayIterator = new RecursiveArrayIterator($data); 66 67// 作成したクラスのインスタンスを生成します。 68// コンストラクタにイテレータを渡すだけで、プロパティが自動的に設定されます。 69$walker = new MyRecursiveTreeWalker($arrayIterator); 70 71// 内容を表示します。 72$walker->displayLeafNodes(); 73 74/* 75 * 期待される出力: 76 * --- Tree Leaves --- 77 * name: Taro Yamada 78 * 0: PHP 79 * 1: JavaScript 80 * status: completed 81 * status: in-progress 82 */
このサンプルコードは、多次元配列のような階層構造を持つデータを順番に処理するための RecursiveIteratorIterator クラスの使い方を示したものです。
RecursiveIteratorIterator の __construct メソッドは、新しいインスタンスを生成する際に呼び出されます。第1引数 $iterator には、処理したいデータを持つ再帰的なイテレータ(この例では RecursiveArrayIterator)を指定します。第2引数 $mode は動作モードを決定し、デフォルトの RecursiveIteratorIterator::LEAVES_ONLY は階層の末端にある要素(葉)のみを対象とすることを意味します。第3引数 $flags で追加の動作を設定できます。このコンストラクタ自体に戻り値はありません。
また、MyRecursiveTreeWalker クラスでは、PHP 8.0の新機能「コンストラクタのプロパティ昇格」が使われています。コンストラクタの引数に private などのアクセス修飾子を付けることで、プロパティの宣言と引数の代入を同時に行い、コードを簡潔に記述できます。
コードの実行の流れとして、まず多次元配列から RecursiveArrayIterator を作成します。次に、それを MyRecursiveTreeWalker のコンストラクタに渡してインスタンスを生成します。内部で RecursiveIteratorIterator が準備され、displayLeafNodes メソッドが呼び出されると、階層の末端にある値が順番に出力されます。
コンストラクタのプロパティ昇格は、PHP 8.0から導入された機能のため、古いバージョンでは構文エラーになります。この機能は、引数で受け取った値をクラスのプロパティへ自動で設定しますが、サンプルコードのように、そのプロパティを使ってさらに別のオブジェクトを生成する処理は別途記述する必要があります。また、RecursiveIteratorIterator のコンストラクタは Traversable 型の引数を必要とします。そのため、多次元配列を扱う場合は、RecursiveArrayIterator などを使ってイテレータオブジェクトに変換してから渡さなければなりません。配列を直接渡すと型エラーが発生するので注意してください。
PHP RecursiveIteratorIterator の construct で親クラスを呼び出す
1<?php 2 3/** 4 * RecursiveIteratorIteratorを継承し、独自の機能を追加するサンプルクラスです。 5 * 6 * このクラスは、親クラスのコンストラクタを呼び出すことで、 7 * RecursiveIteratorIteratorの基本機能を利用しつつ、 8 * 独自のプロパティ(この場合はログ用のプレフィックス)を初期化します。 9 */ 10class LoggingRecursiveIterator extends RecursiveIteratorIterator 11{ 12 /** 13 * @var string ログ出力時に各行の先頭に付加する文字列 14 */ 15 private string $logPrefix; 16 17 /** 18 * LoggingRecursiveIterator のコンストラクタ 19 * 20 * 独自の引数 `$logPrefix` を受け取り、残りの引数は親クラスのコンストラクタに渡します。 21 * 22 * @param Traversable $iterator 反復処理の対象となるイテレータ 23 * @param string $logPrefix ログのプレフィックス 24 * @param int $mode イテレーションモード (親クラスのコンストラクタに渡される) 25 */ 26 public function __construct( 27 Traversable $iterator, 28 string $logPrefix = '[LOG]', 29 int $mode = self::LEAVES_ONLY 30 ) { 31 // `parent::__construct` を使用して、親クラスである 32 // `RecursiveIteratorIterator` のコンストラクタを呼び出します。 33 // これにより、イテレータの基本的な初期化処理が実行されます。 34 parent::__construct($iterator, $mode); 35 36 // このクラス独自のプロパティを初期化します。 37 $this->logPrefix = $logPrefix; 38 } 39 40 /** 41 * 現在の要素を返すメソッドをオーバーライドします。 42 * 43 * 親クラスの `current()` メソッドが返す値を取得し、 44 * 独自の処理(ここではログ出力)を追加します。 45 * 46 * @return mixed 47 */ 48 public function current(): mixed 49 { 50 // 親クラスの `current()` を呼び出して、元の値を取得します。 51 $value = parent::current(); 52 53 // 独自の処理として、取得したキーと値をコンソールに出力します。 54 echo sprintf("%s Key: %s, Value: %s\n", $this->logPrefix, $this->key(), $value); 55 56 return $value; 57 } 58} 59 60// サンプルとして使用する多次元配列 61$userProfile = [ 62 'name' => 'Taro Yamada', 63 'contact' => [ 64 'email' => 'taro@example.com', 65 'phone' => '090-1234-5678', 66 ], 67 'interests' => ['Programming', 'Reading'], 68]; 69 70// PHPの組み込みクラス `RecursiveArrayIterator` を使って、配列をイテレータに変換します。 71$arrayIterator = new RecursiveArrayIterator($userProfile); 72 73// 作成したカスタムクラスのインスタンスを生成します。 74// この時点で `LoggingRecursiveIterator::__construct` が呼び出されます。 75$loggingIterator = new LoggingRecursiveIterator($arrayIterator, '[INFO]'); 76 77// `foreach` でループ処理を行うと、オーバーライドした `current()` メソッドが各要素で呼び出されます。 78// ループ自体は空でも、current()内のログ出力処理は実行されます。 79foreach ($loggingIterator as $item) { 80 // このループ内で `$item` を使った処理も可能ですが、 81 // 今回のサンプルでは `current()` 内のログ出力が主目的です。 82}
RecursiveIteratorIteratorクラスのコンストラクタ__constructは、多次元配列などの再帰的なデータ構造を順番に処理するためのイテレータを初期化する、インスタンス生成時に自動で呼び出される特別なメソッドです。
このサンプルコードでは、PHPのRecursiveIteratorIteratorを継承し、独自のログ出力機能を追加したLoggingRecursiveIteratorクラスを作成しています。子クラスのコンストラクタ内でparent::__construct()を呼び出している点が重要です。キーワードparentは親クラスを指し、これを用いることで親クラスであるRecursiveIteratorIteratorのコンストラクタを呼び出し、イテレータとしての基本的な初期化処理を実行させています。
parent::__construct()の第一引数$iteratorには、繰り返し処理の対象となるRecursiveArrayIteratorのインスタンスを渡します。第二引数の$modeはイテレータの振る舞いを決めるモードで、末端の要素のみを対象とするLEAVES_ONLYを指定しています。コンストラクタに戻り値はありません。
親クラスの初期化が完了した後、子クラス独自のプロパティ$logPrefixをセットしています。このようにparent::__construct()を使うことで、親クラスの機能を維持したまま新しい機能を追加したクラスを効率的に作成でき、これはオブジェクト指向における継承の基本的な手法です。
クラスを継承して独自のコンストラクタを定義する際、親クラスの初期化処理を引き継ぐために parent::__construct() を呼び出すことが重要です。これを呼び忘れると、親クラスが持つ機能が正しく動作せず、エラーの原因となります。呼び出す際には、親クラスのコンストラクタが要求する引数を、正しい順序と型で渡す必要があります。parent は、__construct 以外のメソッドを上書き(オーバーライド)する場合にも、親の元の処理を呼び出すために使用する重要なキーワードです。このルールを守ることで、既存のクラスの機能を安全に拡張できます。