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

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

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

作成日: 更新日:

基本的な使い方

readメソッドは、Directoryクラスのインスタンスが指し示すディレクトリの内容を読み込むために使用するメソッドです。このメソッドは、ディレクトリポインタが現在指している位置から、次のエントリの名前(ファイル名またはサブディレクトリ名)を文字列として取得します。

readメソッドが呼び出されるたびに、ディレクトリポインタは自動的に次のエントリに進みます。これにより、ループ処理の中でreadメソッドを繰り返し呼び出すことで、ディレクトリ内のすべてのエントリを一つずつ順に処理することが可能です。すべてのエントリを読み終えて、これ以上エントリが存在しない場合は、readメソッドはfalseを返します。このfalseの戻り値は、通常、ディレクトリの走査を終了する条件として利用されます。

readメソッドは、一般的なファイルやサブディレクトリの名前に加えて、特殊なエントリである「.`」(カレントディレクトリ)と「..」(親ディレクトリ)も返します。これらはUnix系のファイルシステムにおいて標準的なエントリです。

このメソッドを使用する際は、まずDirectory::open()メソッドで対象のディレクトリを開き、その後にreadメソッドでエントリを読み込み、最後にDirectory::close()メソッドでディレクトリリソースを閉じる一連の流れが一般的です。もしディレクトリの読み込み中にエラーが発生した場合、falseが返されることがありますので、戻り値を適切に確認してエラーハンドリングを行うことが重要です。

構文(syntax)

1<?php
2$directory = dir('/path/to/directory'); // Directory クラスのインスタンス
3$entry = $directory->read();
4?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

string|false

Directory::read() メソッドは、ディレクトリ内の次のエントリの名前を文字列で返します。ディレクトリの終わりに達するか、エラーが発生した場合は false を返します。

サンプルコード

PHPでディレクトリ内容とファイル表示

1<?php
2
3/**
4 * 指定されたディレクトリの内容を読み込み、ファイルであればその内容を表示します。
5 * システムエンジニアを目指す初心者向けに、PHPのDirectory::readメソッドとreadfile関数を組み合わせて使用する例です。
6 *
7 * @param string $directoryPath 読み込むディレクトリのパス。
8 */
9function displayDirectoryContentsWithFileRead(string $directoryPath): void
10{
11    // 指定されたパスがディレクトリとして存在するか確認します。
12    if (!is_dir($directoryPath)) {
13        echo "エラー: 指定されたパス '{$directoryPath}' はディレクトリではありません。\n";
14        return;
15    }
16
17    // ディレクトリを開き、Directory オブジェクトを取得します。
18    // PHP 8では、dir() 関数は Directory オブジェクトを返します。
19    $dir = dir($directoryPath);
20
21    if ($dir === false) {
22        // dir() が false を返すのは、ディレクトリが存在しないか、開く権限がない場合です。
23        echo "エラー: ディレクトリ '{$directoryPath}' を開けませんでした。\n";
24        return;
25    }
26
27    echo "ディレクトリ '{$directoryPath}' の内容:\n";
28    echo "----------------------------------------\n";
29
30    // Directory::read() メソッドを使用して、ディレクトリ内のエントリ(ファイルやサブディレクトリの名前)を
31    // 一つずつ読み込みます。エントリがなくなるかエラーが発生すると、false を返します。
32    while (($entry = $dir->read()) !== false) {
33        // 特殊なエントリ '.' (現在のディレクトリ) と '..' (親ディレクトリ) はスキップします。
34        if ($entry === '.' || $entry === '..') {
35            continue;
36        }
37
38        // 完全なパスを作成します。
39        $fullPath = rtrim($directoryPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $entry;
40
41        // エントリがディレクトリの場合
42        if (is_dir($fullPath)) {
43            echo "[D] {$entry}\n"; // [D] はディレクトリを示す
44        }
45        // エントリがファイルの場合
46        elseif (is_file($fullPath)) {
47            echo "[F] {$entry} (内容を読み込み中...)\n"; // [F] はファイルを示す
48            echo "-------------------- ファイル内容 START --------------------\n";
49            // readfile() 関数を使用して、ファイルの内容をブラウザやコンソールに直接出力します。
50            // これは、提供されたキーワード 'php readfile' に関連する機能です。
51            // ファイル全体をメモリに読み込まずに出力するため、大きなファイルに適しています。
52            readfile($fullPath);
53            echo "\n-------------------- ファイル内容 END ----------------------\n";
54        }
55        // その他のエントリ(シンボリックリンクなど)の場合
56        else {
57            echo "[?] {$entry} (その他のタイプ)\n";
58        }
59    }
60
61    // ディレクトリリソースを閉じます。
62    $dir->close();
63
64    echo "----------------------------------------\n";
65    echo "処理が完了しました。\n";
66}
67
68// 以下はサンプルコードを実行するためのテスト環境の準備と実行です。
69// このスクリプトと同じディレクトリ内に一時的なテストディレクトリを作成します。
70$testDir = __DIR__ . DIRECTORY_SEPARATOR . 'my_test_directory';
71
72// テストディレクトリが存在しない場合、作成します。
73if (!is_dir($testDir)) {
74    mkdir($testDir);
75}
76
77// テスト用のファイルをいくつか作成します。
78file_put_contents($testDir . DIRECTORY_SEPARATOR . 'sample1.txt', "これはサンプルファイル1の内容です。\nPHP初心者向けメッセージ。\n");
79file_put_contents($testDir . DIRECTORY_SEPARATOR . 'log.log', "2023-01-01 INFO: アプリケーション開始\n2023-01-01 ERROR: エラー発生\n");
80
81// テスト用のサブディレクトリも作成します。
82$subDir = $testDir . DIRECTORY_SEPARATOR . 'sub_folder';
83if (!is_dir($subDir)) {
84    mkdir($subDir);
85}
86file_put_contents($subDir . DIRECTORY_SEPARATOR . 'nested.md', "#  nested.md\nこれはサブディレクトリ内のファイルです。\n");
87
88// 作成したテストディレクトリを対象に、関数を呼び出して内容を表示します。
89displayDirectoryContentsWithFileRead($testDir);
90
91// テスト環境のクリーンアップ(作成したディレクトリとファイルを削除します)。
92// 実際のアプリケーションでは、ファイルの削除は慎重に行う必要があります。
93unlink($testDir . DIRECTORY_SEPARATOR . 'sample1.txt');
94unlink($testDir . DIRECTORY_SEPARATOR . 'log.log');
95unlink($subDir . DIRECTORY_SEPARATOR . 'nested.md');
96rmdir($subDir); // サブディレクトリを削除
97rmdir($testDir); // メインのテストディレクトリを削除
98
99?>

このPHPコードは、指定されたディレクトリの内容を一覧表示し、ファイルであればその中身を読み出して出力する方法を、システムエンジニアを目指す初心者向けに解説しています。

まず、dir()関数で対象のディレクトリを開き、Directoryオブジェクトを取得します。このオブジェクトを通じてディレクトリ操作を行います。

次に、Directoryオブジェクトのread()メソッドをループで繰り返し呼び出します。read()メソッドは引数なしで、ディレクトリ内のファイル名やサブディレクトリ名を一つずつ文字列として返します。読み込むべきエントリがなくなるとfalseを返すため、これを利用してループを終了します。

読み込んだエントリがファイルであることが確認できた場合、readfile()関数を使用して、そのファイルの内容を直接出力します。readfile()は、ファイルをメモリに全て読み込むことなく、内容を標準出力(通常はコンソールやブラウザ)へ直接送るため、特に大きなファイルを扱う際に効率的です。

処理の最後には、close()メソッドで開いたディレクトリリソースを適切に閉じ、システムの資源を解放します。このコードにより、ディレクトリの探索とファイル内容の確認が効率的に行えます。

Directory::read()はディレクトリ内のエントリ名を一つずつ取得し、処理後は必ずclose()メソッドでリソースを解放してください。readfile()はファイルの内容を直接出力するため、特にウェブアプリケーションでユーザー入力に基づくパスを扱う際は、セキュリティリスクに厳重な注意が必要です。不正なパス指定(ディレクトリトラバーサルなど)により意図しないファイルが読まれたり、重要な情報が漏洩する可能性があるため、入力値の検証とサニタイズを徹底してください。また、ディレクトリ内の特殊なエントリである.(カレントディレクトリ)と..(親ディレクトリ)は処理対象から必ずスキップするようにしましょう。

PHP 8.1 readonlyでディレクトリを読む

1<?php
2
3/**
4 * DirectoryReader class to demonstrate reading directory contents using Directory::read()
5 * and the use of readonly properties (available from PHP 8.1).
6 *
7 * For system engineer beginners:
8 * This class encapsulates the logic for reading a directory.
9 * The 'readonly' keyword is used for properties to ensure that once they are initialized
10 * in the constructor, their values cannot be changed later. This helps create more robust
11 * and predictable code by enforcing immutability.
12 */
13class DirectoryReader
14{
15    /**
16     * The path to the directory. Declared as 'readonly' to ensure it cannot be
17     * modified after the object has been constructed.
18     * This makes the directory path immutable for the lifetime of this object.
19     */
20    private readonly string $path;
21
22    /**
23     * An array to store the names of entries found within the directory.
24     * Declared as 'readonly' to ensure the array reference cannot be changed.
25     * Once populated, this specific list of entries is fixed for this object instance.
26     */
27    private readonly array $entries;
28
29    /**
30     * Constructor for DirectoryReader.
31     *
32     * @param string $directoryPath The path to the directory to be read.
33     * @throws InvalidArgumentException If the provided path is not a valid or readable directory.
34     */
35    public function __construct(string $directoryPath)
36    {
37        // Validate that the given path is indeed a directory and is readable.
38        if (!is_dir($directoryPath) || !is_readable($directoryPath)) {
39            throw new InvalidArgumentException("Directory '{$directoryPath}' does not exist or is not readable.");
40        }
41
42        // Initialize the readonly 'path' property. This is the only place it can be set.
43        $this->path = $directoryPath;
44
45        // Populate the readonly 'entries' property by calling a private method
46        // that handles the actual directory reading.
47        $this->entries = $this->readDirectoryContents();
48    }
49
50    /**
51     * Reads all entries from the directory using the internal Directory::read() method.
52     * Skips the special '.' (current directory) and '..' (parent directory) entries.
53     *
54     * @return array An array containing the names of the directory entries.
55     */
56    private function readDirectoryContents(): array
57    {
58        $entries = [];
59        // Open the directory handle using dir(). This function returns an instance
60        // of PHP's built-in Directory class, which provides the read() method.
61        $dirHandle = dir($this->path);
62
63        // A robust check, although the constructor already validates the path.
64        if ($dirHandle === false) {
65            return []; // Should not occur if constructor validation is effective.
66        }
67
68        // Loop through all entries in the directory using Directory::read().
69        // The read() method returns the next entry name as a string, or false if there are no more entries.
70        while (false !== ($entry = $dirHandle->read())) {
71            // Exclude the special directory entries '.' and '..'.
72            if ($entry !== '.' && $entry !== '..') {
73                $entries[] = $entry;
74            }
75        }
76
77        // Close the directory handle to release system resources.
78        $dirHandle->close();
79        return $entries;
80    }
81
82    /**
83     * Returns the directory path associated with this reader instance.
84     * Because the 'path' property is 'readonly', this method will always return
85     * the same path that was set during construction.
86     *
87     * @return string The directory path.
88     */
89    public function getPath(): string
90    {
91        return $this->path;
92    }
93
94    /**
95     * Returns the list of directory entries found.
96     * As the 'entries' property is 'readonly', this method will always return
97     * the initial list of entries discovered during construction.
98     *
99     * @return array An array of directory entry names.
100     */
101    public function getEntries(): array
102    {
103        // Returning the array directly. While the property itself is readonly,
104        // the contents of the array could theoretically be modified externally
105        // if not explicitly copied. For simplicity and beginner focus, this is acceptable.
106        return $this->entries;
107    }
108}

このコードは、指定されたディレクトリの内容を読み込み、管理するDirectoryReaderクラスの例です。PHP 8.1以降で導入されたreadonlyキーワードが使用されており、クラスのプロパティを、コンストラクタで一度初期化された後は変更できないようにします。これにより、意図しない変更を防ぎ、より堅牢で予測しやすいコードを作成できます。

Directory::read()メソッドは、dir()関数で開かれたディレクトリハンドルから、次に利用可能なエントリ(ファイル名やサブディレクトリ名)を一つずつ文字列として取得するために使用されます。このメソッドは引数をとりません。ディレクトリにこれ以上エントリがない場合はfalseを返します。

サンプルコードでは、readDirectoryContentsプライベートメソッド内でwhile (false !== ($entry = $dirHandle->read()))のようにループで利用し、...といった特殊なエントリを除外しながら、ディレクトリ内のすべてのエントリ名を収集しています。読み込みが完了したら、close()メソッドでディレクトリハンドルを閉じ、システムリソースを適切に解放します。readonlyプロパティにより、このクラスで管理されるディレクトリのパスとエントリリストは、オブジェクトの生成後に変更されることがなく、常に初期状態を維持します。

このサンプルコードでは、PHP 8.1以降で導入されたreadonlyプロパティにより、一度設定したディレクトリパスが変更されない堅牢な設計を示しています。Directory::read()メソッドは、ディレクトリ内のエントリ名を文字列で返すか、もうエントリがない場合はfalseを返します。そのため、ループ条件ではfalseとの厳密な比較(!==)を行い、確実に全てのエントリを処理することが重要です。また、dir()関数で開いたディレクトリハンドルは、使用後に必ずclose()メソッドで閉じてシステムリソースを解放してください。ディレクトリの読み込み前に、is_dir()is_readable()でパスの有効性を検証することで、予期せぬエラーを防ぎ、安全なプログラム運用に繋がります。

関連コンテンツ