【PHP8.x】Directory::rewind()メソッドの使い方
rewindメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
rewindメソッドは、Directoryクラスのインスタンスが表すディレクトリの内部ポインタを先頭に戻すメソッドです。
PHPでは、opendir()関数を使ってディレクトリを開くと、そのディレクトリ内のファイルやサブディレクトリなどのエントリを読み込むための内部ポインタが設定されます。このポインタは、readdir()関数などでエントリを一つずつ読み進めるたびに自動的に次の位置へ移動します。全てのディレクトリ内容を読み終えたり、途中で特定の処理を終えてから、再びディレクトリの最初からエントリを読み直したい場合に、この内部ポインタをリセットする必要が生じます。
rewindメソッドを呼び出すと、現在内部ポインタがどこを指しているかに関わらず、そのポインタがディレクトリの最初の位置に戻されます。これにより、再度readdir()関数を呼び出した際には、ディレクトリ内の最初のファイルやサブディレクトリから再び読み込みを開始できるようになります。この機能は、ディレクトリ内のエントリを複数回処理する必要がある場合や、特定の条件に基づいてディレクトリ内容を繰り返し参照する場面で特に役立ちます。rewindメソッドは引数を取らず、特に値を返しませんが、ディレクトリの読み込み状態を初期化する重要な役割を担っています。
構文(syntax)
1<?php 2$directoryObject = opendir('.'); // Directory オブジェクトを生成 3if ($directoryObject) { 4 $directoryObject->rewind(); 5 closedir($directoryObject); 6} 7?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
戻り値なし
戻り値はありません
サンプルコード
DirectoryIterator rewind()で複数回走査する
1<?php 2 3/** 4 * ディレクトリの内容をDirectoryIteratorで複数回走査し、 5 * その途中でrewind()メソッドを使ってイテレータを巻き戻す方法をデモンストレーションします。 6 * これは、PHPのジェネレータが通常1度しか走査できないのに対し、 7 * rewindableな(巻き戻し可能な)イテレータの一例を示します。 8 */ 9function demonstrateDirectoryRewind(): void 10{ 11 // 1. デモンストレーション用に一時ディレクトリとダミーファイルを作成します 12 $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'php_rewind_demo_' . uniqid(); 13 if (!mkdir($tempDir, 0777, true)) { 14 echo "エラー: 一時ディレクトリ '$tempDir' の作成に失敗しました。\n"; 15 return; 16 } 17 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'fileA.txt', 'コンテンツ A'); 18 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'fileB.txt', 'コンテンツ B'); 19 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'fileC.txt', 'コンテンツ C'); 20 21 echo "--- DirectoryIterator::rewind() のデモンストレーション ---\n"; 22 echo "使用する一時ディレクトリ: $tempDir\n\n"; 23 24 try { 25 // DirectoryIteratorのインスタンスを作成します。 26 // これはディレクトリ内のエントリ(ファイルやサブディレクトリ)を反復処理するためのクラスです。 27 $dirIterator = new DirectoryIterator($tempDir); 28 29 echo "最初の走査(ファイル一覧):\n"; 30 foreach ($dirIterator as $fileInfo) { 31 // '.' と '..' エントリは出力から除外します 32 if ($fileInfo->isDot()) { 33 continue; 34 } 35 echo "- " . $fileInfo->getFilename() . "\n"; 36 } 37 38 echo "\nrewind() を呼び出してイテレータをリセットしています...\n\n"; 39 // rewind() メソッドは、イテレータの内部ポインタをディレクトリストリームの先頭にリセットします。 40 // これにより、イテレータは「巻き戻し可能(rewindable)」になり、 41 // 同じディレクトリの内容を複数回走査することができます。 42 // これは、複数回イテレーションを行いたい「rewindable generator」のコンセプトと類似しています。 43 $dirIterator->rewind(); 44 45 echo "2回目の走査(rewind()後):\n"; 46 foreach ($dirIterator as $fileInfo) { 47 if ($fileInfo->isDot()) { 48 continue; 49 } 50 echo "- " . $fileInfo->getFilename() . "\n"; 51 } 52 53 } catch (Exception $e) { 54 echo "エラーが発生しました: " . $e->getMessage() . "\n"; 55 } finally { 56 // 3. デモンストレーション後、一時ディレクトリとファイルをクリーンアップします 57 echo "\n一時ディレクトリをクリーンアップ中...\n"; 58 $files = array_diff(scandir($tempDir) ?: [], ['.', '..']); 59 foreach ($files as $file) { 60 unlink($tempDir . DIRECTORY_SEPARATOR . $file); 61 } 62 rmdir($tempDir); 63 echo "クリーンアップが完了しました。\n"; 64 } 65} 66 67// デモンストレーション関数を実行します 68demonstrateDirectoryRewind();
PHPのDirectoryIteratorクラスは、指定したディレクトリ内のファイルやサブディレクトリを順番に処理(走査)する際に使用する便利な機能です。通常、一度走査を終えたイテレータは、再度最初から内容を読み込むことができません。しかし、DirectoryIteratorオブジェクトのrewind()メソッドを呼び出すことで、このイテレータの内部ポインタがディレクトリの先頭にリセットされ、再び最初から走査を開始できるようになります。
このサンプルコードでは、まずデモンストレーション用に一時ディレクトリとダミーファイルを作成します。次にDirectoryIteratorを使ってディレクトリの内容を一度走査し、ファイル名を表示します。その後、$dirIterator->rewind(); を実行します。このメソッドは引数を持たず、戻り値もありませんが、呼び出すことでイテレータの状態を初期位置に戻します。これにより、2回目の走査で再び同じファイル名の一覧を取得できることを示しています。これは、複数回イテレーション可能な「巻き戻し可能なジェネレータ(rewindable generator)」の概念と類似しています。最後に、作成した一時ディレクトリとファイルを適切にクリーンアップしています。
DirectoryIterator::rewind()は、イテレータをリセットし、ディレクトリ内容を複数回走査可能にする点が重要です。一時リソース生成時はfinallyで必ずクリーンアップし、リソースリークを防ぎましょう。ファイルシステム操作は失敗しやすいため、try-catchで堅牢なエラーハンドリングを実装してください。.や..などの特殊エントリはisDot()で除外必須です。
PHP Directory::rewind() でディレクトリを再読み込みする
1<?php 2 3/** 4 * PHPのDirectory::rewind()メソッドの使用例を示します。 5 * 6 * このスクリプトは、一時的なディレクトリを作成し、その中にいくつかのファイルを作成します。 7 * その後、Directoryオブジェクトを使用してディレクトリの内容を読み込み、 8 * Directory::rewind()メソッドで内部ポインタをリセットし、再度読み込む動作を示します。 9 * スクリプトの実行後、作成した一時ディレクトリとその内容は自動的に削除されます。 10 */ 11 12// テスト用の一時ディレクトリを作成し、サンプルファイルを配置する関数 13function setupTestDirectory(): string 14{ 15 // システムの一時ディレクトリ内にユニークな名前で新しいディレクトリを作成します。 16 $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('php_rewind_test_'); 17 if (!mkdir($tempDir, 0777, true)) { 18 throw new RuntimeException("一時ディレクトリの作成に失敗しました: {$tempDir}"); 19 } 20 21 // テスト用にいくつかのファイルをディレクトリ内に作成します。 22 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'file1.txt', 'Content for file1'); 23 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'file2.txt', 'Content for file2'); 24 mkdir($tempDir . DIRECTORY_SEPARATOR . 'subdir'); // サブディレクトリも作成 25 file_put_contents($tempDir . DIRECTORY_SEPARATOR . 'file3.txt', 'Content for file3'); 26 27 echo "一時ディレクトリを作成しました: " . $tempDir . "\n"; 28 return $tempDir; 29} 30 31// テスト用ディレクトリとその内容をクリーンアップする関数 32function cleanupTestDirectory(string $dirPath): void 33{ 34 // 指定されたパスがディレクトリとして存在しない場合は何もしません。 35 if (!is_dir($dirPath)) { 36 return; 37 } 38 39 // ディレクトリ内のすべてのファイルとサブディレクトリを再帰的に削除します。 40 // RecursiveIteratorIterator は、深くネストされたディレクトリ構造も安全に処理できます。 41 $files = new RecursiveIteratorIterator( 42 new RecursiveDirectoryIterator($dirPath, RecursiveDirectoryIterator::SKIP_DOTS), // . と .. をスキップ 43 RecursiveIteratorIterator::CHILD_FIRST // 子要素から先に処理 (ファイルの削除 -> 空のディレクトリの削除) 44 ); 45 46 foreach ($files as $fileinfo) { 47 if ($fileinfo->isDir()) { 48 rmdir($fileinfo->getRealPath()); // ディレクトリを削除 49 } else { 50 unlink($fileinfo->getRealPath()); // ファイルを削除 51 } 52 } 53 // すべての子要素が削除された後、空になったディレクトリ自体を削除します。 54 rmdir($dirPath); 55 echo "一時ディレクトリを削除しました: " . $dirPath . "\n"; 56} 57 58// Directory::rewind() メソッドの動作を実演するメイン関数 59function demonstrateDirectoryRewind(): void 60{ 61 $testDirPath = ''; // エラー発生時のために初期化。クリーンアップ時に使用します。 62 try { 63 // 1. テスト用のディレクトリとファイルを準備します。 64 $testDirPath = setupTestDirectory(); 65 66 // 2. Directory オブジェクトを初期化します。 67 // このオブジェクトは、指定されたパスのディレクトリを開きます。 68 // PHP 8では、opendir()関数のオブジェクト指向ラッパーとして利用できます。 69 $dir = new Directory($testDirPath); 70 echo "\nディレクトリを開きました: {$testDirPath}\n"; 71 72 // 3. 1回目のディレクトリ内容の読み込み 73 echo "\n--- 1回目のディレクトリ読み込み ---\n"; 74 // read() メソッドは、ディレクトリ内の次のエントリ(ファイル名やサブディレクトリ名)を返します。 75 // エントリがなくなると false を返します。 76 while (($entry = $dir->read()) !== false) { 77 echo " 読み込んだエントリ: " . $entry . "\n"; 78 } 79 echo "1回目の読み込みが完了しました。\n"; 80 81 // 4. Directory::rewind() を呼び出し 82 echo "\n--- Directory::rewind() を呼び出し ---\n"; 83 // rewind() メソッドを呼び出すことで、ディレクトリの内部ポインタが先頭に戻されます。 84 // これにより、再度最初からディレクトリの内容を読み込むことが可能になります。 85 $dir->rewind(); 86 echo "ディレクトリポインタを先頭に戻しました。\n"; 87 88 // 5. 2回目のディレクトリ内容の読み込み (rewind() 呼び出し後) 89 echo "\n--- 2回目のディレクトリ読み込み (rewind() 後) ---\n"; 90 while (($entry = $dir->read()) !== false) { 91 echo " 読み込んだエントリ: " . $entry . "\n"; 92 } 93 echo "2回目の読み込みが完了しました。\n"; 94 95 } catch (Throwable $e) { 96 // 例外が発生した場合、エラーメッセージを表示します。 97 echo "\nエラーが発生しました: " . $e->getMessage() . "\n"; 98 } finally { 99 // 6. テスト用のディレクトリとファイルをクリーンアップします。 100 // スクリプトの実行が成功しても失敗しても、必ずクリーンアップを行います。 101 if ($testDirPath !== '') { // ディレクトリが実際に作成されていた場合のみクリーンアップを実行 102 cleanupTestDirectory($testDirPath); 103 } 104 } 105} 106 107// demonstrateDirectoryRewind 関数を実行して、Directory::rewind() の動作を確認します。 108demonstrateDirectoryRewind();
PHP 8のDirectory::rewind()メソッドは、ディレクトリの内容を読み込むためのDirectoryオブジェクトの内部ポインタを先頭にリセットする際に使用されます。このメソッドは引数を取らず、戻り値もありません。
Directoryクラスは、opendir()関数が返すディレクトリハンドルをオブジェクトとして扱えるようにしたもので、read()メソッドを使ってディレクトリ内のファイルやサブディレクトリの名前を一つずつ読み進めることができます。一度すべてのエントリを読み終えると、read()メソッドはこれ以上読み込むものがなくなり、falseを返します。
しかし、再度ディレクトリの最初から内容を読み込みたい場合、新しいDirectoryオブジェクトを作成し直すのではなく、既存のDirectoryオブジェクトに対してrewind()メソッドを呼び出すことで、内部ポインタを先頭に戻すことができます。これにより、改めてread()メソッドを呼び出すと、最初のエントリから読み込みが再開されます。
提供されたサンプルコードでは、まず一時ディレクトリといくつかのテストファイルを作成します。次に、このディレクトリをDirectoryオブジェクトで開き、read()メソッドで一度すべてのエントリを読み込みます。その後、rewind()メソッドを呼び出してポインタをリセットし、再度read()メソッドで最初からエントリを読み込めることを示しています。これにより、同じディレクトリの内容を複数回処理するシナリオで、リソースを効率的に再利用することが可能になります。スクリプト終了時には作成した一時ディレクトリは自動的に削除されます。
PHPのDirectory::rewind()メソッドは、Directory::read()で読み進めたディレクトリの内部ポインタを先頭に戻すために使われます。このメソッドを呼び出すことで、一度最後まで読み込んだディレクトリの内容を、再度最初から読み直すことが可能になります。もしrewind()を呼ばない場合、read()はそれ以上エントリを返さなくなりますので注意が必要です。ファイルシステム操作では、権限エラーやパスの誤りなどが起こり得るため、サンプルコードのようにtry-catch-finallyで確実にエラーを処理し、一時的に作成したディレクトリなどのリソースを確実にクリーンアップすることが安全なプログラミングにおいて非常に重要です。