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

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

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

作成日: 更新日:

基本的な使い方

getChildrenメソッドは、現在のイテレータ要素が子要素を持つ場合に、その子要素をフィルタリングするための新しいイテレータインスタンスを生成して返すメソッドです。このメソッドは、RecursiveIteratorインターフェースの一部として実装されており、ディレクトリツリーや多次元配列のような階層構造を持つデータを再帰的に処理する際に中心的な役割を果たします。RecursiveCallbackFilterIteratorクラスは、コンストラクタで指定されたコールバック関数を用いて要素をフィルタリングしますが、getChildrenメソッドが呼び出されると、現在の要素の子要素群に対して同じフィルタリングロジックを適用する、新しいRecursiveCallbackFilterIteratorオブジェクトが作成されます。これにより、親の階層だけでなく、子の階層、さらにその孫の階層へと、同じ基準でのフィルタリングを継続的に適用することが可能になります。返される値は、子要素を巡回するための新しいRecursiveCallbackFilterIteratorのインスタンスであり、これを通じて再帰的なフィルタ処理が実現されます。

構文(syntax)

1$childrenIterator = $iterator->getChildren();

引数(parameters)

引数なし

引数はありません

戻り値(return)

RecursiveCallbackFilterIterator

このメソッドは、現在の要素の子要素を探索するために使用される、RecursiveCallbackFilterIterator オブジェクトを返します。

サンプルコード

RecursiveCallbackFilterIterator::getChildren()で子要素をフィルタリングして取得する

1<?php
2
3// Function to create a temporary directory structure for demonstration purposes.
4// This sets up a sample file system for our iterator to traverse.
5function createDemoDirectory(string $basePath): void
6{
7    if (!is_dir($basePath)) {
8        mkdir($basePath, 0777, true);
9    }
10
11    // Create some files and directories within the base path
12    file_put_contents($basePath . '/document.txt', 'This is a main document.');
13    file_put_contents($basePath . '/image.jpg', 'This is an image file.'); // Will be filtered out
14    mkdir($basePath . '/project_files');
15    file_put_contents($basePath . '/project_files/code.txt', 'PHP code snippet.');
16    file_put_contents($basePath . '/project_files/data.csv', 'CSV data.'); // Will be filtered out
17    mkdir($basePath . '/project_files/reports');
18    file_put_contents($basePath . '/project_files/reports/summary.txt', 'Report summary.');
19    mkdir($basePath . '/.temp_cache'); // Will be filtered out
20    file_put_contents($basePath . '/.hidden_log.txt', 'Hidden log content.'); // Will be filtered out
21}
22
23// Function to clean up the temporary directory after the demonstration.
24// This ensures no leftover files or directories.
25function cleanDemoDirectory(string $basePath): void
26{
27    if (!is_dir($basePath)) {
28        return;
29    }
30    // Create iterators to recursively remove all files and directories
31    $it = new RecursiveDirectoryIterator($basePath, RecursiveDirectoryIterator::SKIP_DOTS);
32    $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
33    foreach ($files as $file) {
34        if ($file->isDir()) {
35            rmdir($file->getRealPath()); // Remove directory
36        } else {
37            unlink($file->getRealPath()); // Remove file
38        }
39    }
40    rmdir($basePath); // Remove the base directory itself
41}
42
43// --- Main demonstration code for RecursiveCallbackFilterIterator::getChildren() ---
44
45$tempDir = __DIR__ . '/recursive_getChildren_demo';
46createDemoDirectory($tempDir); // Set up the temporary directory structure
47
48try {
49    // 1. Define a callback function for filtering.
50    // This function decides which items (files or directories) are accepted by the iterator.
51    // It must return true to include an item, false to exclude it.
52    $filterCallback = function (SplFileInfo $current, string $key, RecursiveCallbackFilterIterator $iterator): bool {
53        $filename = $current->getFilename();
54
55        // Exclude the current directory ('.') and parent directory ('..') entries.
56        if ($current->isDot()) {
57            return false;
58        }
59
60        // Exclude any files or directories whose names start with a '.' (e.g., '.git', '.hidden_file.txt').
61        if (str_starts_with($filename, '.')) {
62            return false;
63        }
64
65        // If the item is a directory, always include it. This allows us to potentially traverse into it.
66        if ($current->isDir()) {
67            return true;
68        }
69
70        // For files, only include those with a '.txt' extension.
71        return $current->isFile() && pathinfo($filename, PATHINFO_EXTENSION) === 'txt';
72    };
73
74    // 2. Create a base RecursiveDirectoryIterator for our temporary path.
75    //    The SKIP_DOTS flag automatically excludes '.' and '..' entries.
76    $directoryIterator = new RecursiveDirectoryIterator(
77        $tempDir,
78        RecursiveDirectoryIterator::SKIP_DOTS
79    );
80
81    // 3. Wrap the directory iterator with RecursiveCallbackFilterIterator.
82    //    This new iterator will apply our $filterCallback to each item from the directory iterator.
83    $filteredIterator = new RecursiveCallbackFilterIterator(
84        $directoryIterator,
85        $filterCallback
86    );
87
88    echo "--- Items in the root directory (filtered by callback) ---\n";
89
90    // Iterate through the top-level items that pass the filter.
91    foreach ($filteredIterator as $path => $fileInfo) {
92        echo sprintf("- %s (%s)\n", $fileInfo->getBasename(), $fileInfo->getType());
93
94        // 4. Demonstrate getChildren():
95        //    If the current item is a directory AND it has children that also pass the filter,
96        //    we can use getChildren() to obtain a new iterator for its immediate children.
97        if ($fileInfo->isDir() && $filteredIterator->hasChildren()) {
98            echo sprintf("  [Found directory '%s'. Calling getChildren() to list its filtered contents.]\n", $fileInfo->getBasename());
99
100            // getChildren() returns a *new* RecursiveCallbackFilterIterator instance.
101            // This new iterator is specifically for the children of the current item
102            // and applies the *same* filtering callback.
103            $childrenIterator = $filteredIterator->getChildren();
104
105            echo "  --- Children of '" . $fileInfo->getBasename() . "' (filtered) ---\n";
106            // Iterate through the children provided by the new iterator.
107            foreach ($childrenIterator as $childPath => $childFileInfo) {
108                echo sprintf("    - Child: %s (%s)\n", $childFileInfo->getBasename(), $childFileInfo->getType());
109
110                // We can even call getChildren() recursively on these child directories
111                // if they themselves have filtered children.
112                if ($childFileInfo->isDir() && $childrenIterator->hasChildren()) {
113                    echo sprintf("      [Found child directory '%s'. Calling getChildren() for its filtered contents.]\n", $childFileInfo->getBasename());
114                    $grandChildrenIterator = $childrenIterator->getChildren();
115                    echo "      --- Grandchildren of '" . $childFileInfo->getBasename() . "' (filtered) ---\n";
116                    foreach ($grandChildrenIterator as $grandChildPath => $grandChildFileInfo) {
117                        echo sprintf("        - Grandchild: %s (%s)\n", $grandChildFileInfo->getBasename(), $grandChildFileInfo->getType());
118                    }
119                    echo "      -----------------------------------------\n";
120                }
121            }
122            echo "  -----------------------------------------\n";
123        }
124    }
125
126} catch (Exception $e) {
127    // Catch and display any exceptions that might occur during directory operations or iteration.
128    echo "An error occurred: " . $e->getMessage() . "\n";
129} finally {
130    // Always ensure the temporary directory is cleaned up, even if an error occurred.
131    cleanDemoDirectory($tempDir);
132}
133
134?>

PHPのRecursiveCallbackFilterIterator::getChildren()メソッドは、再帰的なフィルタリング処理において、現在のディレクトリが持つ子要素をさらに探索するために使用されます。このメソッドは引数を取りません。

RecursiveCallbackFilterIteratorは、ディレクトリ内のファイルやフォルダを特定の条件(コールバック関数)に基づいてフィルタリングしながら走査する際に利用されます。getChildren()メソッドは、現在のイテレータがディレクトリを指しており、かつフィルタリング条件に合致する子要素が存在する場合に呼び出します。このメソッドが実行されると、現在のディレクトリの、フィルタリングされた子要素のみを反復処理するための新たなRecursiveCallbackFilterIteratorインスタンスが戻り値として返されます。

サンプルコードでは、隠しファイルや一部のファイルをフィルタリングし、.txtファイルとディレクトリのみを許可する条件を設定しています。メインのループでディレクトリが見つかり、そのディレクトリにフィルタリングされた子要素が存在する場合、getChildren()を使用してその子要素専用のイテレータを取得し、さらにその下の階層を深く探索しています。これにより、同じフィルタリングルールを適用しながら、ディレクトリ構造全体を再帰的に効率よく走査し、必要な要素のみを抽出することが可能になります。

getChildren()メソッドは、現在のイテレータが指す要素がディレクトリであり、かつフィルタリング条件に合致する子要素が存在する場合に、その子要素のみを対象とする新しいRecursiveCallbackFilterIteratorインスタンスを返します。この返されるイテレータにも、元のイテレータに設定された同じフィルタリングルールが適用されるため、常に一貫した条件で子要素を探索できます。getChildren()を呼び出す前にhasChildren()メソッドで子要素の有無を事前に確認することで、より安全かつ効率的に処理を進めることが推奨されます。この方法を再帰的に利用すると、複雑なディレクトリ構造全体を特定の条件でフィルタリングしながら深く探索することが可能になります。

RecursiveCallbackFilterIterator::getChildren()による子要素取得

1<?php
2
3// 一時ディレクトリとファイルをセットアップする関数
4function setupTempFiles(string $baseDir): void
5{
6    $tempDir = $baseDir . '/temp_recursive_filter_test';
7    if (!file_exists($tempDir)) {
8        mkdir($tempDir);
9        mkdir($tempDir . '/sub_dir_a');
10        mkdir($tempDir . '/sub_dir_b');
11        file_put_contents($tempDir . '/file1.php', '<?php echo "PHP file 1";');
12        file_put_contents($tempDir . '/file2.txt', 'Text file 2 content');
13        file_put_contents($tempDir . '/sub_dir_a/file3.php', '<?php echo "PHP file 3 in sub_dir_a";');
14        file_put_contents($tempDir . '/sub_dir_a/file4.log', 'Log file 4 content');
15        file_put_contents($tempDir . '/sub_dir_b/file5.php', '<?php echo "PHP file 5 in sub_dir_b";');
16    }
17}
18
19// 一時ディレクトリとファイルをクリーンアップする関数
20function cleanupTempFiles(string $baseDir): void
21{
22    $tempDir = $baseDir . '/temp_recursive_filter_test';
23    if (is_dir($tempDir)) {
24        // ディレクトリ内のすべてのファイルとサブディレクトリを削除するためにRecursiveIteratorIteratorを使用
25        $it = new RecursiveDirectoryIterator($tempDir, RecursiveDirectoryIterator::SKIP_DOTS);
26        $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
27        foreach ($files as $file) {
28            if ($file->isDir()) {
29                rmdir($file->getRealPath());
30            } else {
31                unlink($file->getRealPath());
32            }
33        }
34        rmdir($tempDir);
35    }
36}
37
38/**
39 * PHPファイルとディレクトリのみを許可するカスタムフィルターイテレータクラス。
40 * RecursiveCallbackFilterIterator を継承し、accept() および hasChildren() メソッドを実装することで、
41 * getChildren() メソッドの動作をデモンストレーションします。
42 */
43class PhpFileAndDirectoryFilterIterator extends RecursiveCallbackFilterIterator
44{
45    /**
46     * 現在の要素がフィルタリング条件に合致するかどうかを判定します。
47     * ディレクトリは常に許可され、ファイルは拡張子が '.php' の場合のみ許可されます。
48     *
49     * @return bool
50     */
51    public function accept(): bool
52    {
53        $current = $this->current();
54        if ($current->isDir()) {
55            return true; // ディレクトリは常に許可します
56        }
57        // ファイルの場合は、拡張子が '.php' のもののみを許可します
58        return $current->isFile() && pathinfo($current->getFilename(), PATHINFO_EXTENSION) === 'php';
59    }
60
61    /**
62     * 現在の要素が子要素を持つかどうかを判定します。
63     * ディレクトリである場合にのみ子要素を持つと判断します。
64     *
65     * @return bool
66     */
67    public function hasChildren(): bool
68    {
69        return $this->current()->isDir();
70    }
71}
72
73// サンプルコードの実行
74$basePath = __DIR__;
75setupTempFiles($basePath); // 一時ディレクトリとファイルをセットアップ
76$targetDir = $basePath . '/temp_recursive_filter_test';
77
78try {
79    echo "--- フィルタリングされたファイルシステムツリーの走査 ---\n";
80
81    // 1. RecursiveDirectoryIterator を作成し、走査したいベースディレクトリを指定します。
82    $directoryIterator = new RecursiveDirectoryIterator($targetDir);
83
84    // 2. 作成したカスタムフィルターイテレータで RecursiveDirectoryIterator をラップします。
85    //    これにより、定義した accept() メソッドに従って要素がフィルタリングされます。
86    $filterIterator = new PhpFileAndDirectoryFilterIterator($directoryIterator);
87
88    // 3. RecursiveIteratorIterator を使用して、フィルタリングされたツリー全体を再帰的に走査します。
89    //    RecursiveIteratorIterator は、内部で RecursiveCallbackFilterIterator::getChildren() メソッドを呼び出し、
90    //    子要素をフィルタリングされた状態で取得し、再帰的な走査を実現します。
91    $recursiveIterator = new RecursiveIteratorIterator($filterIterator, RecursiveIteratorIterator::SELF_FIRST);
92
93    foreach ($recursiveIterator as $path => $fileInfo) {
94        // 現在の要素の深さに応じてインデントをつけ、ツリー構造を視覚化します。
95        echo str_repeat('  ', $recursiveIterator->getDepth());
96        echo ($fileInfo->isDir() ? 'D: ' : 'F: ') . $fileInfo->getFilename() . "\n";
97    }
98
99    echo "\n--- 特定のディレクトリの子要素を getChildren() で直接取得する例 ---\n";
100
101    // 4. RecursiveCallbackFilterIterator::getChildren() メソッドを直接呼び出す例。
102    //    イテレータを特定のディレクトリに移動させ、その子要素をフィルタリングされたイテレータとして取得します。
103
104    // イテレータを巻き戻し、最初の要素から再度処理を開始します。
105    $filterIterator->rewind();
106
107    // 'sub_dir_a' という名前のディレクトリが見つかるまでイテレータを進めます。
108    foreach ($filterIterator as $item) {
109        if ($item->isDir() && $item->getFilename() === 'sub_dir_a') {
110            echo "ディレクトリ 'sub_dir_a' を見つけました。\n";
111            echo "getChildren() を使って、その子要素のイテレータを直接取得します。\n";
112            
113            // 現在のイテレータ($filterIterator)が 'sub_dir_a' を指している状態で
114            // getChildren() を呼び出すと、'sub_dir_a' の子要素をフィルタリングする
115            // 新しい RecursiveCallbackFilterIterator インスタンスが返されます。
116            // この新しいイテレータも、親イテレータと同じフィルタリングロジック(PhpFileAndDirectoryFilterIterator)を適用します。
117            $childrenOfSubDirA = $filterIterator->getChildren();
118            
119            // getChildren() の戻り値の型を確認します。RecursiveCallbackFilterIterator が期待されます。
120            echo "getChildren() の戻り値の型: " . get_class($childrenOfSubDirA) . "\n";
121            
122            echo "'sub_dir_a' のフィルタリングされたコンテンツ:\n";
123            foreach ($childrenOfSubDirA as $child) {
124                echo "  - " . ($child->isDir() ? 'D: ' : 'F: ') . $child->getFilename() . "\n";
125            }
126            break; // 例のために最初に見つかったマッチで終了します
127        }
128    }
129
130} finally {
131    // スクリプトの終了時に、作成した一時ファイルを確実にクリーンアップします。
132    cleanupTempFiles($basePath);
133}
134

PHPのRecursiveCallbackFilterIterator::getChildren()メソッドは、ファイルシステムやデータ構造などを再帰的に走査し、特定の条件で要素をフィルタリングする際に使用されるRecursiveCallbackFilterIteratorクラスの機能です。このメソッドは引数を一切取らず、現在のイテレータが指している要素の子要素を、同じフィルタリングルールが適用された新しいRecursiveCallbackFilterIteratorインスタンスとして返します。

具体的には、ディレクトリを走査している際に、現在のディレクトリの子ファイルやサブディレクトリだけを、指定された条件(例えば、特定の拡張子を持つファイルのみなど)でフィルタリングして取得したい場合に利用します。サンプルコードでは、.phpファイルとディレクトリのみを許可するカスタムフィルタPhpFileAndDirectoryFilterIteratorを作成しています。

RecursiveIteratorIteratorを使用してディレクトリツリー全体を再帰的に走査する場合、getChildren()メソッドは内部的に呼び出され、フィルタリングされた子要素を自動的に取得し、再帰処理を進めます。また、サンプルコードの後半では、特定のディレクトリ(sub_dir_a)の子要素を$filterIterator->getChildren()と直接呼び出すことで、そのディレクトリの直下にあるフィルタリング済みの内容のみを個別に取得できることを示しています。このように、getChildren()はフィルタリングされた状態で子要素のイテレータを提供し、効率的かつ柔軟なデータ走査を可能にする重要なメソッドです。

RecursiveCallbackFilterIterator::getChildren()メソッドは、現在のイテレータが子要素を持つ場合に、その子要素をフィルタリングする新しいRecursiveCallbackFilterIteratorインスタンスを返します。この戻り値には、親イテレータで定義されたフィルタリングロジック(accept()hasChildren())が適用されるため、常にフィルタリングされた結果が得られます。通常、RecursiveIteratorIteratorと組み合わせて使用することで、内部で自動的にgetChildren()が呼び出され、フィルタリングされたツリー全体を再帰的に走査できます。そのため、このメソッドを直接呼び出す機会は多くないかもしれません。直接利用する際は、イテレータが子要素を持つ要素を指しているかを確認することが重要です。

関連コンテンツ

関連IT用語

関連プログラミング言語