目錄遍歷是 PHP 專案常見需求:掃描上傳目錄、建立檔案索引、批次處理檔案等。本文詳解兩種原生函數實作遞迴掃描的完整範例。
function listDir(string $dir): void
{
if (!is_dir($dir)) {
echo "無效目錄: $dir
";
return;
}
$handle = opendir($dir);
if (!$handle) {
echo "無法開啟目錄: $dir
";
return;
}
while (($file = readdir($handle)) !== false) {
// 跳過當前與上層目錄
if ($file === '.' || $file === '..') continue;
$fullPath = $dir . DIRECTORY_SEPARATOR . $file;
if (is_dir($fullPath)) {
echo "📁 目錄: $fullPath
";
listDir($fullPath); // 遞迴
} else {
echo "📄 檔案: $fullPath
";
}
}
closedir($handle);
}
// 使用
listDir('./phpmyadmin');
function tree(string $dir): void
{
$mydir = dir($dir);
if (!$mydir) {
echo "無法開啟目錄: $dir
";
return;
}
while (($file = $mydir->read()) !== false) {
if ($file === '.' || $file === '..') continue;
$fullPath = "$dir/$file";
if (is_dir($fullPath)) {
echo "📁 目錄: $fullPath
";
tree($fullPath);
} else {
echo "📄 檔案: $fullPath
";
}
}
$mydir->close();
}
tree('./phpmyadmin');
function scanDirectory(string $path, array &$result = [], int $depth = 0): array
{
$items = scandir($path);
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$fullPath = $path . DIRECTORY_SEPARATOR . $item;
$info = [
'name' => $item,
'path' => $fullPath,
'type' => is_dir($fullPath) ? 'dir' : 'file',
'depth' => $depth,
'size' => is_file($fullPath) ? filesize($fullPath) : null,
'mtime' => filemtime($fullPath),
];
$result[] = $info;
if ($info['type'] === 'dir') {
scanDirectory($fullPath, $result, $depth + 1);
}
}
return $result;
}
$files = scanDirectory(__DIR__ . '/storage');
// 現在 $files 包含完整結構化資料,可進一步過濾、排序、匯出 JSON 等
| 特性 | readdir() | dir() | scandir() |
|---|---|---|---|
| 記憶體佔用 | 低(流式讀取) | 低(流式讀取) | 高(一次載入所有) |
| 程式碼風格 | 程序式 | 物件導向 | 函數式 |
| 排序控制 | 需自行排序 | 需自行排序 | 預設字母序 |
| 適用場景 | 大型目錄、記憶體敏感 | 偏好 OOP 風格 | 小型目錄、需快速排序 |
is_dir() / opendir() 可能因權限失敗,務必加 @ 或 try-catch(PHP 8+)is_link() 檢測並決定是否跟隨DIRECTORY_SEPARATOR 常數RecursiveDirectoryIterator (SPL) 獲得更好控制$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('./phpmyadmin',
RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
echo ($file->isDir() ? '📁 ' : '📄 ') . $file->getPathname() . "
";
}
// 內建支援過濾、深度限制、排序等進階功能