刪除非空目錄需遞迴刪除所有子檔案與子目錄。本文提供標準遞迴實作、錯誤處理、權限檢查與現代 RecursiveDirectoryIterator 替代方案。
<?php
/**
* 遞迴刪除目錄及其所有內容
*
* @param string $dir 目錄路徑
* @return bool 成功返回 true,失敗拋出異常
*/
function deleteDirectory(string $dir): bool {
// 正規化路徑
$dir = rtrim($dir, '/\\');
if (!is_dir($dir)) {
throw new \InvalidArgumentException("Not a directory: $dir");
}
$items = scandir($dir);
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$path = $dir . DIRECTORY_SEPARATOR . $item;
if (is_dir($path)) {
deleteDirectory($path); // 遞迴刪除子目錄
} else {
if (!unlink($path)) {
throw new \RuntimeException("Failed to delete file: $path");
}
}
}
if (!rmdir($dir)) {
throw new \RuntimeException("Failed to remove directory: $dir");
}
return true;
}
// 使用範例
try {
deleteDirectory('./fakeDir');
echo "目錄刪除成功\n";
} catch (\Exception $e) {
echo "刪除失敗: " . $e->getMessage() . "\n";
}
?>
<?php
function deleteDirectoryModern(string $dir): void {
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST // 先刪除子項,再刪除父目錄
);
foreach ($files as $file) {
if ($file->isDir()) {
rmdir($file->getPathname());
} else {
unlink($file->getPathname());
}
}
rmdir($dir);
}
?>
RecursiveDirectoryIterator::SKIP_DOTS:自動跳過 . 和 ..。RecursiveIteratorIterator::CHILD_FIRST:深度優先,子節點先於父節點處理(刪除必需)。is_writable($dir) 與 is_writable($file)。rename()),確認無誤再永久刪除。| 方法 | 程式碼行數 | 可讀性 | 效能 |
|---|---|---|---|
| 遞迴函數 | ~20 | 直觀 | 良好 |
| RecursiveIterator | ~10 | 宣告式 | 略優(C 實作迭代器) |