在 PHP 開發中,遍歷目錄下所有文件(包含子目錄)是常見需求。雖然遞歸寫法直觀,但深層目錄可能導致堆疊溢位或效能問題。本文介紹如何使用堆疊(Stack)模擬遞歸,實現非遞歸的目錄遍歷,並提供兩種實用代碼範例供參考。
遞歸本質是系統自動管理的呼叫堆疊。我們可以用陣列手動模擬:
$stack,將起始目錄壓入。scanfiles()此函數回傳所有文件的完整路徑陣列,兼容 Windows/Unix 路徑分隔符。
/**
* 非遞歸掃描目錄下所有文件
* @param string $dir 目錄路徑
* @return array 文件路徑陣列
*/
function scanfiles($dir) {
if (!is_dir($dir)) return [];
// 統一路徑分隔符並確保結尾有斜線
$dir = rtrim(str_replace('\\', '/', $dir), '/') . '/';
$stack = [$dir];
$files = [];
do {
$currentDir = array_pop($stack);
$entries = scandir($currentDir);
foreach ($entries as $entry) {
if ($entry === '.' || $entry === '..') continue;
$path = $currentDir . $entry;
if (is_dir($path)) {
$stack[] = $path . '/';
} elseif (is_file($path)) {
$files[] = $path;
}
}
} while ($stack);
return $files;
}
scanAll() 並解決順序問題此版本直接輸出路徑,邏輯更簡潔。注意 scandir() 返回順序導致壓棧順序反向,需用 array_reverse() 修正。
/**
* 遍歷目錄並輸出所有文件/目錄路徑
* @param string $dir 起始目錄
*/
function scanAll($dir) {
$stack = [$dir];
while (count($stack) > 0) {
$path = array_pop($stack);
echo $path . "\r\n";
if (is_dir($path)) {
// 反轉順序,使輸出與遞歸版一致
$children = array_reverse(scandir($path));
foreach ($children as $child) {
if ($child !== '.' && $child !== '..') {
$stack[] = $path . '/' . $child;
}
}
}
}
}
scanAll2()function scanAll2($dir) {
echo $dir . "\r\n";
if (is_dir($dir)) {
$children = scandir($dir);
foreach ($children as $child) {
if ($child !== '.' && $child !== '..') {
scanAll2($dir . '/' . $child);
}
}
}
}
掌握堆疊模擬遞歸是進階 PHP 開發者的基本功。根據項目需求選擇合適方式,並注意路徑分隔符兼容與掃描順序控制,即可高效完成目錄遍歷任務。