【PHP8.x】RecursiveRegexIterator::USE_KEY定数の使い方
USE_KEY定数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
USE_KEY定数は、RecursiveRegexIteratorクラスが正規表現によるマッチング処理を行う対象を指定するための定数です。RecursiveRegexIteratorは、配列やオブジェクトのようなデータの集まりを再帰的にたどりながら、指定された正規表現パターンに一致する要素を見つけ出すためのクラスです。通常、このクラスはデータの「値」に対して正規表現のマッチングを行いますが、USE_KEY定数をコンストラクタのモード引数に指定することで、その動作を変更できます。この定数を指定した場合、マッチングの対象が「値」ではなく、各要素の「キー」になります。これにより、例えば「id_」や「config_」といった特定の接頭辞を持つキーの要素だけを抽出するなど、キーの名称に基づいた柔軟なフィルタリング処理を実現できます。データのキー自体に意味のある情報が含まれている場合に、この定数を用いることで効率的なデータ操作が可能となります。
構文(syntax)
1<?php 2 3$array = [ 4 'match_key_1' => 'Value A', 5 'skip_this_key' => 'Value B', 6 'nested_array' => [ 7 'match_key_2' => 'Value C', 8 'skip_this_too' => 'Value D', 9 ], 10]; 11 12$arrayIterator = new RecursiveArrayIterator($array); 13 14// The regex '/^match/' will be applied to the iterator keys. 15$regexIterator = new RecursiveRegexIterator( 16 $arrayIterator, 17 '/^match/', 18 RecursiveRegexIterator::USE_KEY 19); 20 21$iterator = new RecursiveIteratorIterator($regexIterator); 22 23foreach ($iterator as $key => $value) { 24 // Outputs only the items where the key starts with "match". 25 echo "{$key}: {$value}" . PHP_EOL; 26}
引数(parameters)
引数なし
引数はありません
戻り値(return)
戻り値なし
戻り値はありません
サンプルコード
PHP RecursiveRegexIterator::USE_KEY を使う
1<?php 2 3/** 4 * RecursiveRegexIterator::USE_KEY 定数の動作をデモンストレーションします。 5 * この定数は、イテレータのキーを正規表現に一致した文字列に設定します。 6 * 7 * システムエンジニアを目指す初心者向けに、一時ファイルを作成・使用し、 8 * 単体で動作可能なコードとしています。 9 */ 10function demonstrateRecursiveRegexIteratorWithUseKey(): void 11{ 12 // ① テスト用のディレクトリとファイルを準備します。 13 // この関数が単体で動作するために一時的なファイルを作成します。 14 $testBaseDir = __DIR__ . '/temp_recursive_regex_test'; 15 16 // 既にテストディレクトリが存在する場合は、前回の実行結果をクリーンアップします。 17 if (is_dir($testBaseDir)) { 18 _cleanupTestFiles($testBaseDir); 19 } 20 _createTestFiles($testBaseDir); 21 22 echo "--- RecursiveRegexIterator::USE_KEY のデモンストレーション ---\n"; 23 echo "検索対象ディレクトリ: " . realpath($testBaseDir) . "\n\n"; 24 25 // ② RecursiveDirectoryIterator を使って、指定されたディレクトリを再帰的に走査します。 26 // SKIP_DOTS は . と .. ディレクトリを除外するためのフラグです。 27 $dirIterator = new RecursiveDirectoryIterator($testBaseDir, RecursiveDirectoryIterator::SKIP_DOTS); 28 29 // RecursiveIteratorIterator を使って、RecursiveDirectoryIterator の結果を再帰的に処理します。 30 // SELF_FIRST は、ディレクトリ自体をその内容よりも先に返すためのフラグです。 31 $recursiveIterator = new RecursiveIteratorIterator($dirIterator, RecursiveIteratorIterator::SELF_FIRST); 32 33 // ③ RecursiveRegexIterator を使って、特定のパターンに一致するファイル名をフィルタリングします。 34 // 今回は拡張子が .txt のファイルを対象とします。 35 // 正規表現は、各ファイルパス(RecursiveDirectoryIterator が返すパス)に対して適用されます。 36 37 // RecursiveRegexIterator::USE_KEY を使用した場合の例 38 // このフラグを設定すると、イテレータのキーが正規表現に「一致した文字列」になります。 39 // 今回の正規表現 (`/^.+\.txt$/i`) はファイルのフルパス全体にマッチするため、 40 // キーもファイルのフルパスになります。 41 $regexIteratorWithUseKey = new RecursiveRegexIterator( 42 $recursiveIterator, 43 '/^.+\.txt$/i', // `.txt` で終わるファイル名を検索(フルパスに適用) 44 RecursiveRegexIterator::GET_MATCH, // マッチした文字列の配列を返すモード 45 RecursiveRegexIterator::USE_KEY // イテレータのキーを正規表現に一致した文字列にするフラグ 46 ); 47 48 echo "--- USE_KEY を使用した場合の検索結果 (キーは正規表現に一致した文字列) ---\n"; 49 foreach ($regexIteratorWithUseKey as $key => $value) { 50 // $key は RecursiveRegexIterator::USE_KEY の影響で、正規表現に一致した文字列 (フルパス) になります。 51 // $value[0] にはマッチした文字列全体 (フルパス) が入ります。 52 echo "キー: {$key}\n"; 53 echo " 値 (フルパス): {$value[0]}\n"; 54 } 55 echo "\n"; 56 57 // 比較のために RecursiveRegexIterator::USE_KEY を使用しない場合の例 58 // この場合、キーは親イテレータ (RecursiveIteratorIterator) のデフォルトのキーになります。 59 // RecursiveDirectoryIterator と RecursiveIteratorIterator のデフォルトのキーはファイルのフルパスです。 60 $regexIteratorWithoutUseKey = new RecursiveRegexIterator( 61 $recursiveIterator, 62 '/^.+\.txt$/i', // `.txt` で終わるファイル名を検索(フルパスに適用) 63 RecursiveRegexIterator::GET_MATCH // マッチした文字列の配列を返すモード 64 // RecursiveRegexIterator::USE_KEY は指定しない 65 ); 66 67 echo "--- USE_KEY を使用しない場合の検索結果 (キーは親イテレータのデフォルトのキー) ---\n"; 68 foreach ($regexIteratorWithoutUseKey as $key => $value) { 69 // $key は親イテレータのデフォルトのキー (フルパス) になります。 70 // $value[0] にはマッチした文字列全体 (フルパス) が入ります。 71 echo "キー: {$key}\n"; 72 echo " 値 (フルパス): {$value[0]}\n"; 73 } 74 echo "\n"; 75 76 // ④ テスト用のファイルをクリーンアップします。 77 _cleanupTestFiles($testBaseDir); 78 echo "--- クリーンアップ完了 ---\n"; 79} 80 81/** 82 * テスト用のファイルとディレクトリを作成します。 83 * (この関数は demonstrateRecursiveRegexIteratorWithUseKey() の内部ヘルパーです) 84 * 85 * @param string $baseDir ベースディレクトリのパス 86 */ 87function _createTestFiles(string $baseDir): void 88{ 89 if (!is_dir($baseDir)) { 90 mkdir($baseDir, 0777, true); // ディレクトリを再帰的に作成 91 } 92 file_put_contents($baseDir . '/document1.txt', 'これは最初のテキストファイルです。'); 93 file_put_contents($baseDir . '/image.jpg', 'これは画像ファイルです。'); 94 mkdir($baseDir . '/subfolder', 0777, true); 95 file_put_contents($baseDir . '/subfolder/document2.txt', 'これは2番目のテキストファイルです。'); 96 file_put_contents($baseDir . '/subfolder/log.log', 'これはログファイルです。'); 97} 98 99/** 100 * テスト用のファイルとディレクトリを削除します。 101 * (この関数は demonstrateRecursiveRegexIteratorWithUseKey() の内部ヘルパーです) 102 * 103 * @param string $baseDir ベースディレクトリのパス 104 */ 105function _cleanupTestFiles(string $baseDir): void 106{ 107 if (!is_dir($baseDir)) { 108 return; 109 } 110 // ディレクトリ内のファイルを再帰的に削除 111 $it = new RecursiveDirectoryIterator($baseDir, RecursiveDirectoryIterator::SKIP_DOTS); 112 $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST); 113 foreach ($files as $file) { 114 if ($file->isDir()) { 115 rmdir($file->getRealPath()); // ディレクトリを削除 116 } else { 117 unlink($file->getRealPath()); // ファイルを削除 118 } 119 } 120 rmdir($baseDir); // ベースディレクトリを削除 121} 122 123// デモンストレーション関数を実行します。 124demonstrateRecursiveRegexIteratorWithUseKey();
PHPのRecursiveRegexIterator::USE_KEY定数は、RecursiveRegexIteratorクラスで使用され、イテレータのキーの挙動を制御するフラグです。この定数自体には引数や戻り値はありません。
通常、RecursiveRegexIteratorは、親イテレータ(このサンプルコードではRecursiveIteratorIterator)から受け取った要素のキーをそのまま使用します。しかし、このUSE_KEY定数をRecursiveRegexIteratorのコンストラクタに指定すると、イテレータのキーが正規表現に「一致した文字列」に設定されるようになります。
サンプルコードでは、一時的なファイルを作成し、指定されたディレクトリから.txt拡張子を持つファイルを再帰的に検索しています。USE_KEY定数を指定したRecursiveRegexIteratorの例では、foreachループで取得される$keyが、正規表現に一致したファイルのフルパスとなります。一方、USE_KEYを指定しない場合の$keyは、親イテレータが提供するデフォルトのキー(この場合もファイルのフルパス)となります。これにより、USE_KEYがキーの値をどのように変更するかを明確に比較して示しています。この定数は、特定の正規表現マッチ結果を直接キーとして扱いたい場合に役立ちます。
RecursiveRegexIterator::USE_KEY定数は、イテレータのキーを正規表現に「一致した文字列」に設定します。サンプルでは正規表現がファイルのフルパス全体にマッチするためキーもフルパスとなりますが、正規表現によってはキーがファイル名の一部など異なる内容になります。USE_KEYを使用しない場合、キーは親イテレータのデフォルト値(この例ではフルパス)です。両者で結果が同じに見えても、キーが決定される元が異なりますので、その違いを理解することが大切です。一時的なファイルやディレクトリを作成するコードでは、必ずクリーンアップ処理を含め、リソース管理を適切に行うよう心がけてください。
PHPクロージャでuseキーワードを使う
1<?php 2 3/** 4 * 外部の変数をクロージャ(無名関数)に渡す `use` キーワードの例。 5 * 6 * この関数は、配列の各要素に特定の係数を掛ける処理を行います。 7 * `use` キーワードは、クロージャのスコープ外で定義された `$multiplier` 変数を 8 * クロージャ内で利用可能にするために使用されます。 9 * 10 * @param array $numbers 数値の配列 11 * @param int $multiplier 各要素に掛ける係数 12 * @return array 処理後の配列 13 */ 14function applyMultiplierToNumbers(array $numbers, int $multiplier): array 15{ 16 // クロージャのスコープ外で定義された $multiplier 変数を 17 // クロージャ内で利用するために `use` キーワードを使用します。 18 $processedNumbers = array_map(function (int $number) use ($multiplier) { 19 return $number * $multiplier; 20 }, $numbers); 21 22 return $processedNumbers; 23} 24 25// サンプルデータ 26$myNumbers = [1, 2, 3, 4, 5]; 27$factor = 10; 28 29// 関数を実行し、結果を出力 30echo "元の配列: " . implode(", ", $myNumbers) . PHP_EOL; 31echo "乗数: " . $factor . PHP_EOL; 32 33$result = applyMultiplierToNumbers($myNumbers, $factor); 34 35echo "乗算後の配列: " . implode(", ", $result) . PHP_EOL; 36 37?>
このPHPのサンプルコードは、PHP 8で利用可能なクロージャ(無名関数)において、外部の変数を内部で利用するためのuseキーワードの働きを説明しています。
useキーワードは、クロージャが定義されたスコープの外にある変数を、クロージャの内部スコープに取り込むために使用されます。これにより、クロージャは、まるで自身の引数であるかのように外部の変数を参照し、それに基づいて処理を実行することが可能になります。
サンプルコードのapplyMultiplierToNumbers関数は、数値の配列$numbersと、各要素に掛ける係数$multiplierを引数に受け取ります。この関数内では、array_map関数とクロージャを組み合わせています。array_mapは、配列の各要素に指定されたコールバック関数(この場合クロージャ)を適用し、その結果から新しい配列を生成する関数です。
クロージャはfunction (int $number) use ($multiplier)と定義されており、ここでuse ($multiplier)が重要な役割を果たします。applyMultiplierToNumbers関数の引数である$multiplier変数が、このuseキーワードによってクロージャの内部で利用できるようになります。クロージャは、渡された数値$numberに外部から取り込んだ$multiplierを掛けた結果を返します。
最終的に、applyMultiplierToNumbers関数は、元の配列のすべての要素に乗数が適用された新しい配列を戻り値として返します。この例では、[1, 2, 3, 4, 5]の各要素に10が掛けられ、結果として[10, 20, 30, 40, 50]という配列が出力されます。このようにuseキーワードを利用することで、柔軟で再利用性の高いコードを記述できます。
useキーワードは、クロージャ(無名関数)が定義された時点の外部変数の値を、クロージャの内部で利用できるようにするものです。これにより、クロージャが独立した処理を行いつつ、必要な外部データにアクセスできます。基本的に値渡しとなるため、クロージャ内で取り込んだ変数を変更しても、元の外部変数には影響しません。もし外部変数をクロージャ内で変更し、その変更を外部にも反映させたい場合は、use (&$variable)のようにアンパサンド(&)を付けて参照渡しにする必要があります。しかし、これは意図しない副作用を引き起こす可能性があるため、利用する際は十分に注意してください。また、サンプルコードのように引数や戻り値に型ヒントを記述することは、コードの安全性と可読性を高める良い習慣です。