【PHP8.x】SCANDIR_SORT_NONE定数の使い方
SCANDIR_SORT_NONE定数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
SCANDIR_SORT_NONE定数は、PHPのscandir()関数を用いてディレクトリ内の項目を一覧表示する際に、その結果をソートしないことを指定するための定数です。scandir()関数は、指定されたディレクトリにあるファイルやサブディレクトリの名前を配列として返しますが、この定数を第二引数に渡すことで、結果が自動的にアルファベット順などに並べ替えられることなく、ファイルシステムが提供する順序、あるいはPHPの内部的な順序でそのまま返されます。
この定数を使用する主な目的は、ソート処理が不要な場合や、アプリケーション側で独自の順序付けを行いたい場合に、余分な処理を省くことです。特に多くの項目を扱うディレクトリでは、ソート処理がシステムのリソースを消費し、実行時間に影響を与えることがあります。そのため、SCANDIR_SORT_NONEを指定することで、不要なソートを行わないように明示的に指示し、プログラムのパフォーマンス向上に貢献できます。
scandir()関数では、デフォルトで昇順ソートを行うSCANDIR_SORT_ASCENDINGや、降順ソートを行うSCANDIR_SORT_DESCENDINGといった他のソートオプションも利用できますが、SCANDIR_SORT_NONEはこれらのソートを完全に無効化するための選択肢として提供されています。これにより、開発者は必要に応じて柔軟にファイルリストの取得方法を制御できます。
構文(syntax)
1scandir('/path/to/directory', SCANDIR_SORT_NONE);
引数(parameters)
引数なし
引数はありません
戻り値(return)
戻り値なし
戻り値はありません
サンプルコード
PHP: scandirでファイルのみをソートせずに取得する
1<?php 2 3/** 4 * 指定されたディレクトリ内のファイルのみを取得し、ソートせずに返します。 5 * 6 * SCANDIR_SORT_NONE 定数を使用することで、ファイルシステムから読み込まれた順序で 7 * 結果が返され、ソート処理によるオーバーヘッドを避けることができます。 8 * 9 * @param string $directoryPath 検索対象のディレクトリパス 10 * @return array<string> ディレクトリ内のファイル名の配列。取得に失敗した場合は空の配列。 11 */ 12function getFilesOnlyUnsorted(string $directoryPath): array 13{ 14 // scandir関数は、指定されたディレクトリ内のすべてのファイルとディレクトリをリストアップします。 15 // SCANDIR_SORT_NONE オプションは、結果をソートしないことを指示します。 16 // これにより、ファイルシステムから返された順序(OS依存)でリストが作成されます。 17 $items = scandir($directoryPath, SCANDIR_SORT_NONE); 18 19 // scandirがディレクトリへのアクセスに失敗した場合(例: 存在しないパス、権限不足)、 20 // falseを返すため、その場合は空の配列を返して処理を終了します。 21 if ($items === false) { 22 return []; 23 } 24 25 $files = []; 26 foreach ($items as $item) { 27 // '.' と '..' は現在のディレクトリと親ディレクトリを示す特殊なエントリなのでスキップします。 28 if ($item === '.' || $item === '..') { 29 continue; 30 } 31 32 // 各項目のフルパスを作成します。 33 // DIRECTORY_SEPARATOR はOSに応じたパス区切り文字(例: '/' または '\')です。 34 $fullPath = $directoryPath . DIRECTORY_SEPARATOR . $item; 35 36 // is_file関数を使用して、現在の項目がファイルであるかどうかを確認します。 37 // is_file() はシンボリックリンクの場合、それが指すターゲットがファイルであればtrueを返します。 38 if (is_file($fullPath)) { 39 $files[] = $item; // ファイルであれば結果の配列に追加します。 40 } 41 } 42 43 return $files; 44} 45 46// --- サンプル使用例 --- 47// このスクリプトが実行されている現在のディレクトリを対象とします。 48// 同じディレクトリにいくつかのテスト用ファイルやサブディレクトリを作成して試してみてください。 49$targetDirectory = __DIR__; // __DIR__ は現在のスクリプトのディレクトリパスを返します。 50 51echo "ディレクトリ: '{$targetDirectory}' 内のファイル(ソートなし):\n"; 52 53$filesInDirectory = getFilesOnlyUnsorted($targetDirectory); 54 55if (!empty($filesInDirectory)) { 56 foreach ($filesInDirectory as $file) { 57 echo "- " . $file . "\n"; 58 } 59} else { 60 echo "ファイルが見つからないか、ディレクトリにアクセスできませんでした。\n"; 61} 62 63?>
このPHPサンプルコードは、指定されたディレクトリ内から「ファイルのみ」を抽出し、その名前をソートせずに取得するgetFilesOnlyUnsorted関数を提供します。scandir関数はディレクトリ内の全てのファイルとディレクトリをリストアップしますが、この関数では第二引数にSCANDIR_SORT_NONE定数を指定しています。これは結果をソートしないことを意味し、ファイルシステムから読み込まれたそのままの順序(OS依存)でリストが返されるため、余計なソート処理による負荷を避けることができます。
getFilesOnlyUnsorted関数は、まずscandirで項目を取得し、もし失敗した場合は空の配列を返して処理を終了します。次に、取得した項目から、現在のディレクトリを示す「.」と親ディレクトリを示す「..」という特殊なエントリを除外します。その後、is_file関数を用いて、それぞれの項目が実際にファイルであるかを確認し、ファイルであると判断された項目のみを結果の配列に追加します。引数として検索対象のディレクトリパス(文字列)を受け取り、戻り値としてディレクトリ内のファイル名の配列(文字列の配列)を返します。ファイルが見つからないか、ディレクトリへのアクセスに失敗した場合は空の配列が返されます。このコードは、ディレクトリからファイルのリストを効率的に取得したい場合に役立ちます。
SCANDIR_SORT_NONEは、ファイルリストをソートしないため、処理のオーバーヘッドを削減し、パフォーマンス向上に役立ちます。scandir関数は、指定されたディレクトリが存在しない場合やアクセス権がない場合、falseを返すため、必ずこの戻り値をチェックして安全に処理を継続してください。取得したリストには、カレントディレクトリを示す「.」と親ディレクトリを示す「..」の特殊なエントリが必ず含まれるため、これらを適切にスキップする必要があります。ファイルとディレクトリを区別するにはis_file()関数などを利用し、DIRECTORY_SEPARATORでOSに依存しないパスを構築することが、コードの堅牢性を高めます。
PHP scandirでディレクトリのみをソートせず取得する
1<?php 2 3/** 4 * 指定されたディレクトリ内のサブディレクトリのみを、ソートせずにリストアップします。 5 * 6 * この関数は scandir() の SCANDIR_SORT_NONE 定数を使用し、 7 * ファイルシステムの自然な順序(通常はディレクトリにエントリが追加された順序)で結果を返します。 8 * 結果の順序はファイルシステムやOS、またはファイルが作成された順序に依存し、予測不能です。 9 * 10 * @param string $directoryPath 検索対象のディレクトリパス。 11 * @return array<string> サブディレクトリ名のリスト。エラー時は空の配列を返します。 12 */ 13function getSubdirectoriesOnly(string $directoryPath): array 14{ 15 // ディレクトリが存在し、読み取り可能かチェックします。 16 // エラー時には空の配列を返し、処理を中断します。 17 if (!is_dir($directoryPath) || !is_readable($directoryPath)) { 18 // 本来はエラーログに出力したり、例外をスローしたりすることが推奨されます。 19 // システムエンジニアを目指す初心者向けには、簡単なメッセージ出力も有効です。 20 // error_log("エラー: ディレクトリ '{$directoryPath}' が存在しないか、読み取りできません。"); 21 return []; 22 } 23 24 $subdirectories = []; 25 26 // scandir を使用してディレクトリの内容を取得します。 27 // 第2引数に SCANDIR_SORT_NONE を指定することで、結果がソートされません。 28 $items = scandir($directoryPath, SCANDIR_SORT_NONE); 29 30 // scandir が失敗した場合 (例: アクセス権がない、パスが不正など) のハンドリング 31 if ($items === false) { 32 // error_log("エラー: ディレクトリ '{$directoryPath}' のスキャンに失敗しました。"); 33 return []; 34 } 35 36 foreach ($items as $item) { 37 // カレントディレクトリ(.)と親ディレクトリ(..)は除外します。 38 if ($item === '.' || $item === '..') { 39 continue; 40 } 41 42 // 現在のアイテムの完全なパスを構築します。 43 $fullPath = rtrim($directoryPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $item; 44 45 // アイテムがディレクトリであるかチェックします。 46 if (is_dir($fullPath)) { 47 $subdirectories[] = $item; 48 } 49 } 50 51 return $subdirectories; 52} 53 54// --- 使用例 --- 55// このスクリプトが存在するディレクトリを対象としてテストします。 56// 必要に応じて、$targetDirectory のパスを別のディレクトリに変更してください。 57$targetDirectory = __DIR__; 58 59// テスト用のサブディレクトリとファイルを作成します (存在しない場合のみ)。 60// このコードは単体動作確認用であり、実際のアプリケーションでは不要です。 61if (!is_dir($targetDirectory . DIRECTORY_SEPARATOR . 'test_subdir_A')) { 62 mkdir($targetDirectory . DIRECTORY_SEPARATOR . 'test_subdir_A'); 63 file_put_contents($targetDirectory . DIRECTORY_SEPARATOR . 'test_file.txt', 'This is a test file.'); 64 mkdir($targetDirectory . DIRECTORY_SEPARATOR . 'test_subdir_B'); 65} 66 67echo "ディレクトリ '{$targetDirectory}' 内のサブディレクトリ一覧(ソートなし):\n"; 68$foundSubdirs = getSubdirectoriesOnly($targetDirectory); 69 70if (empty($foundSubdirs)) { 71 echo " サブディレクトリは見つかりませんでした。\n"; 72} else { 73 foreach ($foundSubdirs as $dirName) { 74 echo "- " . $dirName . "\n"; 75 } 76} 77 78// 作成したテストファイルをクリーンアップしたい場合は、以下のコメントを解除してください。 79// rmdir($targetDirectory . DIRECTORY_SEPARATOR . 'test_subdir_A'); 80// rmdir($targetDirectory . DIRECTORY_SEPARATOR . 'test_subdir_B'); 81// unlink($targetDirectory . DIRECTORY_SEPARATOR . 'test_file.txt');
このPHPサンプルコードは、指定されたディレクトリの中からサブディレクトリだけを抽出し、その名前をソートせずに一覧表示する方法を示しています。
メインとなるgetSubdirectoriesOnly関数は、検索したいディレクトリのパスを文字列として引数に受け取ります。この関数は、見つかったサブディレクトリ名の文字列配列を戻り値として返しますが、エラーが発生した場合は空の配列を返します。
関数は最初に、指定されたディレクトリが存在し、かつ読み取り可能かを確認します。もしディレクトリが見つからなかったり、アクセス権がなかったりした場合は、そこで処理を中断し空の配列を返します。
次に、PHPの組み込み関数scandir()を使用して、ディレクトリ内のすべてのファイルやディレクトリを取得します。ここで重要なのが、scandir()の第2引数にSCANDIR_SORT_NONE定数を指定している点です。この定数を指定することで、scandir()は取得したアイテムをアルファベット順などでソートせず、ファイルシステムが内部的に保持する順序で結果を返します。この順序は、ファイルやディレクトリが作成された順番やオペレーティングシステムに依存するため、実行するたびに異なる場合があり、予測できません。
取得したアイテムはループ処理で一つずつ確認されます。ループ内では、現在のディレクトリを表す「.」と親ディレクトリを表す「..」を除外し、is_dir()関数を使って、現在のアイテムが実際にディレクトリであるかどうかを判定します。ディレクトリと判断された場合のみ、その名前を結果の配列に追加していきます。
サンプルコードの後半では、この関数がどのように利用されるかの具体例が示されており、現在のスクリプトがあるディレクトリを対象に、テスト用のサブディレクトリを作成し、その一覧を表示する流れを確認できます。
SCANDIR_SORT_NONE定数を使用した場合、取得されるディレクトリの順序はファイルシステムやOSに依存するため、実行ごとに異なる可能性があることに注意してください。これは予測不可能な挙動となる場合があります。サンプルコードでは、ディレクトリの存在確認や読み取り権限、scandir関数の失敗を丁寧にチェックし、エラー時には空の配列を返すことで堅牢性を高めています。しかし、実運用では、エラーメッセージのログ出力や例外のスローといった、より具体的なエラーハンドリングを導入することが推奨されます。また、カレントディレクトリ「.」と親ディレクトリ「..」は必ず除外する処理が必要です。ディレクトリパスを結合する際は、OSに依存しないようDIRECTORY_SEPARATOR定数を使うのがベストプラクティスです。サンプル中のディレクトリ作成やファイル書き込みはテスト用のコードですので、本番環境では削除してください。