首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP遞歸遍歷目錄並統計文件/子目錄數量:高效實現與優化建議

     編輯:PHP 相關知識

目錄遞歸掃描:從基礎遞歸到 SPL 迭代器的進化

常見需求:統計項目代碼行數、清理臨時文件、生成站點地圖。本文對比三種實現方式並給出生產環境推薦方案。

方式一:傳統遞歸函數(教學用)

<?php
function scanDirRecursive(string $dir, int &$dirCount, int &$fileCount): void {
    $handle = opendir($dir);
    while (($entry = readdir($handle)) !== false) {
        if ($entry === '.' || $entry === '..') continue;
        $path = $dir . DIRECTORY_SEPARATOR . $entry;
        if (is_dir($path)) {
            $dirCount++;
            scanDirRecursive($path, $dirCount, $fileCount);
        } else {
            $fileCount++;
        }
    }
    closedir($handle);
}
$dirs = $files = 0;
scanDirRecursive('/var/www/html', $dirs, $files);
echo "目錄: $dirs, 文件: $files\n";

缺點:深層目錄易棧溢出、無法輕鬆過濾/排序、效率較低(重複 `stat` 系統調用)。

方式二:RecursiveDirectoryIterator + RecursiveIteratorIterator(推薦)

<?php
function scanWithSPL(string $root): array {
    $dirCount = $fileCount = 0;
    $flags = FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS;
    $iter = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($root, $flags),
        RecursiveIteratorIterator::SELF_FIRST
    );
    foreach ($iter as $path => $info) {
        if ($info->isDir()) $dirCount++;
        else $fileCount++;
    }
    return ['dirs' => $dirCount, 'files' => $fileCount];
}
print_r(scanWithSPL('/var/www/html'));

優勢:C 層實現極快、自動處理遞歸、支援過濾器(`RegexIterator`)、可獲取 `SplFileInfo` 完整元數據(大小、時間、權限)。

方式三:GlobIterator(非遞歸、單層極快)

$count = count(new GlobIterator('/var/www/html/*.php', FilesystemIterator::SKIP_DOTS));
// 僅統計根目錄下 .php 文件

進階:自定義過濾器(如排除 vendor、.git、node_modules)

$skipDirs = ['vendor', '.git', 'node_modules', 'storage', 'bootstrap/cache'];
$filter = new RegexIterator(
    new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS),
    '/^((?!' . implode('|', $skipDirs) . ').)*$/'
);
$iter = new RecursiveIteratorIterator($filter, RecursiveIteratorIterator::SELF_FIRST);

性能對比(萬級文件目錄)

工程化封裝類

<?php
class DirectoryScanner {
    public function __construct(
        private string $root,
        private array $excludeDirs = ['vendor', '.git', 'node_modules'],
        private ?string $pattern = null // 如 '/\.php$/'
    ) {}

    public function stats(): array {
        $dirs = $files = $bytes = 0;
        $filter = new RecursiveCallbackFilterIterator(
            new RecursiveDirectoryIterator($this->root, FilesystemIterator::SKIP_DOTS),
            fn($current, $key, $iterator) => !$current->isDir() || !in_array($current->getBasename(), $this->excludeDirs)
        );
        $iter = new RecursiveIteratorIterator($filter, RecursiveIteratorIterator::SELF_FIRST);
        foreach ($iter as $info) {
            if ($info->isDir()) $dirs++;
            elseif ($this->pattern === null || preg_match($this->pattern, $info->getPathname())) {
                $files++;
                $bytes += $info->getSize();
            }
        }
        return compact('dirs', 'files', 'bytes');
    }
}
print_r((new DirectoryScanner('/var/www/html', pattern: '/\.php$/'))->stats());

使用 SPL 迭代器,代碼更健壯、效率更高、功能更強,是現代 PHP 目錄操作的標準姿勢。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法耗時內存峰值備註
遞歸函數~1.2s~8MBPHP 函數調用開銷大
SPL 迭代器~0.3s~4MBC 層遍歷,推薦生產用
shell `find`~0.15s~1MB需 `exec` 權限,跨平台差