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

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

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

作成日: 更新日:

基本的な使い方

『ParentIterator::__constructメソッドは、ParentIteratorクラスの新しいインスタンスを生成する処理を実行するメソッドです。このメソッドは、親要素を取得したい対象となる再帰イテレータを引数として受け取ります。引数には、PHPの標準機能であるSPL(Standard PHP Library)に含まれるRecursiveIteratorインターフェースを実装したイテレータのインスタンスを指定する必要があります。RecursiveIteratorは、ディレクトリ構造のような階層的なデータを再帰的にたどるための仕組みです。例えば、ファイルシステムを走査するRecursiveDirectoryIteratorをこのコンストラクタに渡すことで、そのイテレータが指す現在の要素(ファイルやサブディレクトリ)の親ディレクトリを指す、新しいParentIteratorオブジェクトが作成されます。この操作により、元のイテレータが階層構造のどの深さにいても、その親要素にアクセスするための準備が整います。このように__constructメソッドは、ParentIteratorが機能するための基礎となる、対象イテレータの初期設定を行う重要な役割を担っています。

構文(syntax)

1<?php
2
3$data = [
4    'first_level_1' => [
5        'second_level_1_1',
6        'second_level_1_2',
7    ],
8    'first_level_2' => [
9        'second_level_2_1',
10    ],
11];
12
13$recursiveIterator = new RecursiveArrayIterator($data);
14
15// ParentIterator::__construct(RecursiveIterator $iterator) の構文
16$parentIterator = new ParentIterator($recursiveIterator);
17
18foreach ($parentIterator as $key => $value) {
19    echo $key . PHP_EOL;
20}
21
22?>

引数(parameters)

RecursiveIterator $iterator

  • RecursiveIterator $iterator: 親イテレータの基盤となるRecursiveIteratorオブジェクト

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PHP8 プロパティ昇格でイテレータをラップする

1<?php
2declare(strict_types=1);
3
4/**
5 * ParentIteratorのコンストラクタを模倣し、
6 * PHP 8の「コンストラクタのプロパティ昇格」機能を示すカスタムクラスです。
7 *
8 * このクラスは内部的にRecursiveIteratorを保持し、
9 * IteratorIteratorとして振る舞います。
10 */
11class CustomParentIterator extends IteratorIterator
12{
13    /**
14     * コンストラクタ。
15     *
16     * PHP 8の「コンストラクタのプロパティ昇格 (Constructor Property Promotion)」を使用しています。
17     * 引数にアクセス修飾子 (private) を付けることで、同名のプロパティの宣言と
18     * コンストラクタ内での代入 (`$this->iterator = $iterator;`) を同時に行えます。
19     * 'readonly' はプロパティが一度初期化された後に変更されないことを保証します (PHP 8.1+)。
20     *
21     * @param RecursiveIterator $iterator ラップするイテレータ
22     */
23    public function __construct(private readonly RecursiveIterator $iterator)
24    {
25        // 親クラスであるIteratorIteratorのコンストラクタを呼び出します。
26        parent::__construct($iterator);
27    }
28
29    /**
30     * 内部で保持しているイテレータのクラス名を取得するデモ用メソッドです。
31     *
32     * @return string
33     */
34    public function getInnerIteratorClassName(): string
35    {
36        return get_class($this->iterator);
37    }
38}
39
40// サンプル用の多次元配列データ
41$data = [
42    'Web Development' => [
43        'PHP',
44        'JavaScript',
45    ],
46    'Database' => [
47        'MySQL',
48        'PostgreSQL',
49    ],
50];
51
52// 配列を再帰的に走査できるイテレータに変換します。
53$arrayIterator = new RecursiveArrayIterator($data);
54$recursiveIterator = new RecursiveIteratorIterator(
55    $arrayIterator,
56    RecursiveIteratorIterator::SELF_FIRST
57);
58
59// イテレータを使ってデータを走査します。
60foreach ($recursiveIterator as $key => $value) {
61    // 現在の要素が子を持つ(=配列である)場合
62    if ($recursiveIterator->hasChildren()) {
63        echo "親カテゴリ: {$key}\n";
64
65        // 子要素のイテレータを取得します。
66        $childrenIterator = $recursiveIterator->getChildren();
67
68        // プロパティ昇格を利用したカスタムクラスのインスタンスを生成します。
69        // 引数で渡した $childrenIterator が、自動的に private readonly プロパティに格納されます。
70        $customIterator = new CustomParentIterator($childrenIterator);
71
72        echo "  - 内部イテレータクラス: " . $customIterator->getInnerIteratorClassName() . "\n";
73
74        // カスタムイテレータを使って子要素を一覧表示します。
75        foreach ($customIterator as $childKey => $childValue) {
76            echo "    - {$childValue}\n";
77        }
78    }
79}

このサンプルコードは、ParentIteratorクラスのコンストラクタを模倣し、PHP 8で導入された「コンストラクタのプロパティ昇格」という便利な機能を説明するものです。

CustomParentIteratorというカスタムクラスには、__constructというコンストラクタが定義されています。コンストラクタは、クラスから新しいインスタンスを生成する際に自動的に呼び出される特別なメソッドで、戻り値はありません。このコンストラクタは、引数としてRecursiveIterator型のオブジェクトを受け取ります。

PHP 8からの新機能「コンストラクタのプロパティ昇格」は、__construct(private readonly RecursiveIterator $iterator)のように、引数の前にprivatereadonlyといった修飾子を記述することで利用できます。この一行だけで、クラス内にiteratorという名前のプロパティを宣言し、コンストラクタで受け取った引数の値をそのプロパティへ代入する、という2つの処理を同時に行えます。これにより、従来よりもコードを短く、簡潔に記述することが可能になります。

実際の動作部分では、多次元配列から取得した子要素のイテレータをCustomParentIteratorに渡しています。このとき、プロパティ昇格の機能によって、渡されたイテレータがインスタンス内部のプロパティとして自動的に保持され、後続の処理で利用される仕組みが示されています。

このコードのポイントは、PHP 8.0からの新機能「コンストラクタのプロパティ昇格」です。コンストラクタの引数にprivateなどのアクセス修飾子を付けるだけで、プロパティの宣言と値の代入を同時に行えるため、コードが簡潔になります。また、PHP 8.1から使えるreadonly修飾子は、一度初期化されたプロパティの変更を防ぎ、不変なオブジェクトを作る際に役立ちます。これにより、予期せぬ値の上書きを防ぎ、コードの安全性が高まります。クラスを継承する際はparent::__construct()を忘れずに呼び出しましょう。親クラスの初期化処理を実行するために必要で、特にIteratorIteratorのようなクラスでは、この呼び出しがないと正しく機能しません。

PHP ParentIterator constructで親要素を取得する

1<?php
2
3declare(strict_types=1);
4
5// 子を持つ可能性のある多次元配列を定義します。
6$data = [
7    'fruits' => ['apple', 'banana', 'cherry'], // 親要素 (子を持つ)
8    'vegetables' => ['carrot', 'potato'],       // 親要素 (子を持つ)
9    'dairy' => 'milk',                          // 親ではない (子を持たない)
10    'tools' => [],                              // 親要素 (子は空だが配列であるため)
11];
12
13// 多次元配列を再帰的に反復処理するためのRecursiveArrayIteratorを作成します。
14$recursiveIterator = new RecursiveArrayIterator($data);
15
16// ParentIteratorのコンストラクタ(__construct)にRecursiveIteratorを渡してインスタンスを生成します。
17// このイテレータは、子を持つ要素(親)のみを反復処理の対象とします。
18$parentIterator = new ParentIterator($recursiveIterator);
19
20echo "子を持つ親要素のキーのみを一覧表示します:" . PHP_EOL;
21
22// ParentIteratorをforeachでループします。
23foreach ($parentIterator as $key => $value) {
24    // $key には親要素のキー ('fruits', 'vegetables', 'tools') が入ります。
25    // $value は子要素を持つイテレータオブジェクトです。
26    printf("- 親キー: %s" . PHP_EOL, $key);
27}
28
29?>

ParentIterator::__constructは、ParentIteratorの新しいインスタンスを作成するためのコンストラクタです。このParentIteratorは、多次元配列のような入れ子構造のデータの中から、子要素を持つ「親」要素だけを抽出して処理するための機能を提供します。

コンストラクタは、引数としてRecursiveIteratorオブジェクトを1つ受け取ります。これは、どのデータを反復処理の対象にするかを指定するためのものです。サンプルコードでは、配列$dataを再帰的に扱えるようにしたRecursiveArrayIteratorのインスタンスを渡しています。これにより、ParentIteratorは配列$dataを走査し、その中から親要素を探す準備が整います。

このコンストラクタによって生成されたインスタンスは、foreachなどでループ処理を行う際、値が配列である要素(つまり子を持つ要素)のみを返します。サンプルコードでは、キーが'fruits''vegetables''tools'の要素が対象となり、値が文字列の'dairy'は無視されます。

このメソッドはコンストラクタであるため、特定の値を返すことはありません。その役割は、引数で渡されたイテレータを内部に設定し、親要素のみをフィルタリングする機能を持つ新しいParentIteratorオブジェクトを生成することです。

ParentIteratorのコンストラクタには、RecursiveArrayIteratorなどRecursiveIteratorを実装したオブジェクトを渡す必要があります。通常の配列は直接渡せません。このイテレータは、値が配列やオブジェクトのように子要素を持てる構造のものを「親」と判断します。そのため、値が文字列や数値の要素は処理対象外となります。サンプルコードの'tools' => []のように、中身が空の配列も親として扱われる点に注意してください。また、foreachループで得られる値は子要素のイテレータオブジェクトです。子の具体的な値(例: 'apple')を得るには、さらにループ処理などが必要です。

関連コンテンツ