【PHP8.x】RecursiveCallbackFilterIterator::current()メソッドの使い方
currentメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
『currentメソッドは、イテレータの現在の位置にある要素を返す処理を実行するメソッドです』
このメソッドは、RecursiveCallbackFilterIteratorクラスにおいて、フィルタリング条件を満たした現在の要素を取得するために使用されます。RecursiveCallbackFilterIteratorは、コンストラクタで指定されたコールバック関数を使い、再帰的なイテレータ内の要素を一つずつ評価し、コールバック関数がtrueを返した要素のみを有効なものとして扱います。foreach文などでイテレータを反復処理する際、まずvalidメソッドによって現在の位置が有効かどうかが確認されます。その位置が有効であれば、このcurrentメソッドが内部的に呼び出され、その位置にある実際の要素の値を取得します。返される値の型は、元となるイテレータが含む要素の型に依存するためmixed型となります。これにより、開発者はフィルタリング後のコレクションから、条件に合致した現在の要素を安全かつ簡単に取り出すことができます。
構文(syntax)
1<?php 2 3$filesystem = [ 4 'document.txt', 5 'photo.jpg', 6 'archive' => [ 7 'report.txt', 8 'data.csv', 9 'backup.zip' 10 ], 11 'manual.txt' 12]; 13 14$arrayIterator = new RecursiveArrayIterator($filesystem); 15 16$filterIterator = new RecursiveCallbackFilterIterator( 17 $arrayIterator, 18 function ($current, $key, $iterator) { 19 if ($iterator->hasChildren()) { 20 return true; 21 } 22 return str_ends_with($current, '.txt'); 23 } 24); 25 26$iterator = new RecursiveIteratorIterator($filterIterator); 27 28$iterator->rewind(); 29while ($iterator->valid()) { 30 $currentValue = $iterator->current(); 31 echo $currentValue . PHP_EOL; 32 $iterator->next(); 33}
引数(parameters)
引数なし
引数はありません
戻り値(return)
mixed
現在位置にある要素を返します。返される型は要素によって異なります。
サンプルコード
PHP: カレントディレクトリからログファイルを探す
1<?php 2 3declare(strict_types=1); 4 5/** 6 * カレントディレクトリとそのサブディレクトリから特定のファイルを見つけ出すクラス。 7 * 8 * このサンプルでは、RecursiveCallbackFilterIterator を使用して、 9 * カレントディレクトリ配下にある拡張子が「.log」のファイルのみを再帰的に検索し、 10 * そのパス一覧を表示します。 11 */ 12class LogFileFinder 13{ 14 /** 15 * 指定されたパスからログファイルを検索して表示します。 16 * 17 * @param string $path 検索を開始するディレクトリのパス 18 */ 19 public function find(string $path): void 20 { 21 // 動作確認のための一時的なディレクトリとファイルを作成 22 $tempDir = $path . DIRECTORY_SEPARATOR . 'test_dir_' . uniqid(); 23 mkdir($tempDir . DIRECTORY_SEPARATOR . 'logs', 0777, true); 24 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'app.php', '<?php // script'); 25 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'system.log', 'system log'); 26 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . 'access.log', 'access log'); 27 28 echo "検索対象ディレクトリ: {$tempDir}\n"; 29 echo "--------------------------------------------------\n"; 30 echo "拡張子が '.log' のファイルを検索します...\n"; 31 32 try { 33 // ディレクトリを再帰的に走査するイテレータを作成 34 $directoryIterator = new RecursiveDirectoryIterator( 35 $tempDir, 36 RecursiveDirectoryIterator::SKIP_DOTS 37 ); 38 39 // フィルタリング条件を定義するコールバック関数 40 $filterCallback = function (SplFileInfo $current, string $key, RecursiveIterator $iterator): bool { 41 // サブディレクトリも探索対象とするため、ディレクトリは常に許可 42 if ($iterator->hasChildren()) { 43 return true; 44 } 45 // ファイルの場合、ファイル名が '.log' で終わるもののみを許可 46 return $current->isFile() && str_ends_with($current->getFilename(), '.log'); 47 }; 48 49 // RecursiveCallbackFilterIterator でイテレータをフィルタリング 50 $filterIterator = new RecursiveCallbackFilterIterator($directoryIterator, $filterCallback); 51 52 // フィルタリングされた結果を再帰的にたどるためのイテレータ 53 $recursiveIterator = new RecursiveIteratorIterator($filterIterator); 54 55 // foreach ループでフィルタリング結果を処理 56 // ループの各反復で、内部的に current() メソッドが呼び出され、 57 // 現在の要素 (SplFileInfoオブジェクト) が $fileInfo に代入されます。 58 foreach ($recursiveIterator as $fileInfo) { 59 // current() で取得したオブジェクトのメソッドでパス名を表示 60 echo $fileInfo->getPathname() . "\n"; 61 } 62 } finally { 63 // 後片付け: 作成した一時的なディレクトリとファイルを削除 64 $this->cleanup($tempDir); 65 } 66 } 67 68 /** 69 * 指定されたディレクトリとその中身を再帰的に削除します。 70 * 71 * @param string $dirPath 削除するディレクトリのパス 72 */ 73 private function cleanup(string $dirPath): void 74 { 75 if (!is_dir($dirPath)) { 76 return; 77 } 78 79 $items = new RecursiveIteratorIterator( 80 new RecursiveDirectoryIterator($dirPath, RecursiveDirectoryIterator::SKIP_DOTS), 81 RecursiveIteratorIterator::CHILD_FIRST 82 ); 83 84 foreach ($items as $item) { 85 if ($item->isDir()) { 86 rmdir($item->getRealPath()); 87 } else { 88 unlink($item->getRealPath()); 89 } 90 } 91 rmdir($dirPath); 92 echo "--------------------------------------------------\n"; 93 echo "一時ディレクトリをクリーンアップしました。\n"; 94 } 95} 96 97// クラスのインスタンスを作成し、カレントディレクトリ ('.') を対象に検索を実行 98$finder = new LogFileFinder(); 99$finder->find('.');
RecursiveCallbackFilterIteratorクラスのcurrent()メソッドは、フィルタリングされたイテレータが現在指している要素を取得する役割を持ちます。このサンプルコードでは、カレントディレクトリとそのサブディレクトリを再帰的に探索し、拡張子が.logのファイルを見つけ出しています。
foreachループが$recursiveIteratorを処理する際、ループが一周するたびにcurrent()メソッドが内部的に自動で呼び出されます。そして、フィルタリング条件に合致した現在のファイル情報が$fileInfo変数に代入されます。このメソッドに引数はありません。戻り値の型はmixedですが、このコードの文脈では、ファイルやディレクトリの情報を保持するSplFileInfoオブジェクトが返されます。
$fileInfoにはSplFileInfoオブジェクトが格納されているため、$fileInfo->getPathname()のように、そのオブジェクトが持つメソッドを呼び出すことができます。これにより、条件に一致したファイルのフルパスを取得して画面に表示することが可能になっています。
foreachループでイテレータを処理する際、current()メソッドはコードに書かなくても内部で自動的に呼び出され、現在の要素を取得します。このサンプルコードでcurrent()が返す値は、ファイルパスの文字列ではなく、ファイル情報を扱うSplFileInfoオブジェクトです。そのため、ループ内の変数$fileInfoでgetPathname()のようなオブジェクト専用のメソッドを呼び出すことができます。フィルタ用の関数では、サブディレクトリ内も探索するために、ディレクトリ自体を常に許可する処理が重要です。この判定がないと、下層のファイルを見つけることができません。また、検索の起点となるカレントディレクトリはスクリプトの実行場所によって変わるため注意が必要です。
PHP RecursiveCallbackFilterIteratorで最近のファイルを取得する
1<?php 2 3/** 4 * 指定したディレクトリ内を再帰的に検索し、 5 * 特定のタイムスタンプ(現在から1時間以内)より新しいファイルのみを一覧表示します。 6 * RecursiveCallbackFilterIterator を使用してファイルをフィルタリングし、 7 * foreach ループ内で current() メソッド(暗黙的に呼び出される)を使って 8 * フィルタリング後の現在のファイル情報を取得します。 9 */ 10function displayRecentFiles(): void 11{ 12 // --- 準備: テスト用のディレクトリとファイルを作成 --- 13 $baseDir = __DIR__ . '/test_dir'; 14 if (!is_dir($baseDir)) { 15 mkdir($baseDir . '/subdir', 0777, true); 16 } 17 // 現在時刻のファイル 18 touch($baseDir . '/recent.txt'); 19 // 30分前のファイル 20 touch($baseDir . '/subdir/recent_in_subdir.log', time() - 1800); 21 // 2時間前のファイル(これは表示されないはず) 22 touch($baseDir . '/old.txt', time() - 7200); 23 echo "テスト用のディレクトリとファイルを作成しました。\n"; 24 echo "----------------------------------------\n"; 25 26 // --- メイン処理: RecursiveCallbackFilterIterator の使用 --- 27 28 // フィルタリングの基準となるタイムスタンプ(現在から1時間前) 29 $thresholdTimestamp = time() - 3600; 30 31 // 1. ディレクトリを再帰的に走査するイテレータを作成 32 $directoryIterator = new RecursiveDirectoryIterator( 33 $baseDir, 34 FilesystemIterator::SKIP_DOTS 35 ); 36 37 // 2. フィルタリング用のコールバック関数を定義 38 // この関数は、イテレータの各要素に対して実行される 39 $filterCallback = function (SplFileInfo $current, string $key, RecursiveIterator $iterator) use ($thresholdTimestamp): bool { 40 // ディレクトリは除外し、ファイルのみを対象とする 41 if ($current->isFile()) { 42 // ファイルの最終更新日時(タイムスタンプ)が、基準より新しいか判定 43 return $current->getMTime() > $thresholdTimestamp; 44 } 45 return true; // ディレクトリ自体は走査対象として残す 46 }; 47 48 // 3. コールバック関数を使ってフィルタリングを行うイテレータを作成 49 $filterIterator = new RecursiveCallbackFilterIterator( 50 $directoryIterator, 51 $filterCallback 52 ); 53 54 // 4. 再帰的なイテレータをフラットに処理するためにラップする 55 $iterator = new RecursiveIteratorIterator($filterIterator); 56 57 echo "最近1時間以内に更新されたファイル:\n"; 58 // foreachでループすると、フィルタリング条件を満たした要素のみが取得される 59 // 各ループで、変数 $fileInfo にはイテレータの現在の要素が格納される 60 // これは内部的に $iterator->current() を呼び出した結果と同じ 61 foreach ($iterator as $fileInfo) { 62 // $fileInfo は SplFileInfo オブジェクト 63 $fileName = $fileInfo->getPathname(); 64 $timestamp = $fileInfo->getMTime(); 65 printf( 66 "- %s (最終更新: %s)\n", 67 $fileName, 68 date('Y-m-d H:i:s', $timestamp) 69 ); 70 } 71 echo "----------------------------------------\n"; 72 73 74 // --- 後片付け: テスト用のディレクトリとファイルを削除 --- 75 $files = new RecursiveIteratorIterator( 76 new RecursiveDirectoryIterator($baseDir, FilesystemIterator::SKIP_DOTS), 77 RecursiveIteratorIterator::CHILD_FIRST 78 ); 79 foreach ($files as $fileinfo) { 80 if ($fileinfo->isDir()) { 81 rmdir($fileinfo->getRealPath()); 82 } else { 83 unlink($fileinfo->getRealPath()); 84 } 85 } 86 rmdir($baseDir); 87 echo "テスト用のディレクトリとファイルを削除しました。\n"; 88} 89 90// 関数を実行 91displayRecentFiles();
RecursiveCallbackFilterIterator::current()メソッドは、フィルタリング条件を満たしたイテレータが、現在指し示している要素を取得します。このメソッドはforeachループでイテレータを処理する際に内部的に呼び出されるため、開発者が直接コードに記述することはほとんどありません。
サンプルコードでは、指定したディレクトリを再帰的に検索し、ファイルの最終更新タイムスタンプが1時間以内のものだけを抽出しています。foreach ($iterator as $fileInfo)のループが実行されると、PHPは内部で自動的に$iterator->current()を呼び出します。その結果、フィルタリング条件を通過した現在のファイル情報(SplFileInfoオブジェクト)が、変数$fileInfoに格納されます。ループが次の要素に進むたびに、current()は次の条件に合致した要素を返します。
このメソッドに引数はありません。戻り値の型はmixedで、イテレータの現在の要素そのものを返します。このサンプルコードの場合、戻り値はファイル情報を保持するSplFileInfoオブジェクトとなり、そこからファイルパスや更新日時といった詳細情報を取得できます。
foreach ループでイテレータを処理すると、各繰り返しで変数 $fileInfo に現在の要素が代入されます。これは、ループの内部で $iterator->current() メソッドが自動的に呼び出された結果と同じです。このサンプルコードでは、current() はフィルタリング条件を満たしたファイルの情報を SplFileInfo オブジェクトとして返します。そのため、$fileInfo->getPathname() のようにオブジェクトのメソッドを使ってファイルパスなどの詳細情報を取得できます。フィルタリングの核となるコールバック関数では、true を返した要素のみが foreach の対象となります。ディレクトリ自体は常に true を返すことで、サブディレクトリ内のファイルも漏れなく検索される仕組みです。