PHP项目Symfony finder与迭代

wen PHP项目 2

本文目录导读:

PHP项目Symfony finder与迭代

  1. 基础 Finder 迭代
  2. 常用的迭代方法
  3. 高级迭代模式
  4. 带内容的迭代处理
  5. 性能优化迭代
  6. 多目录迭代
  7. 实用示例:文件校验器
  8. 注意事项

我来详细介绍 Symfony Finder 组件的迭代使用:

基础 Finder 迭代

use Symfony\Component\Finder\Finder;
$finder = new Finder();
$finder->files()->in('/path/to/directory');
// 直接迭代文件
foreach ($finder as $file) {
    echo $file->getRealPath() . "\n";
    echo $file->getFilename() . "\n";
}

常用的迭代方法

1 过滤迭代

$finder = new Finder();
// 只找 PHP 文件
$finder->files()
    ->in(__DIR__ . '/src')
    ->name('*.php')
    ->notName('*Test.php');
// 带条件的迭代
foreach ($finder as $file) {
    // 只处理大于 1KB 的文件
    if ($file->getSize() > 1024) {
        echo $file->getFilename() . " - " . $file->getSize() . " bytes\n";
    }
}

2 排序迭代

$finder->files()
    ->in('/path')
    ->sortByName();          // 按文件名排序
// 或
$finder->sortByModifiedTime();  // 按修改时间排序
foreach ($finder as $file) {
    echo $file->getFilename() . " - " . date('Y-m-d H:i:s', $file->getMTime()) . "\n";
}

高级迭代模式

1 使用回调过滤

$finder = new Finder();
$finder->files()
    ->in('/path')
    ->filter(function (\SplFileInfo $file) {
        // 只保留最近7天内修改的文件
        if ($file->getMTime() > strtotime('-7 days')) {
            return true;
        }
        return false;
    });
// 迭代并处理
$finder->getIterator(); // 获取迭代器对象

2 深度控制

$finder->files()
    ->in('/project')
    ->depth('< 2')       // 只搜索1-2层目录
    ->depth('>= 1')      // 至少搜索1层
    ->depth(['< 3', '> 1']); // 2-3层

的迭代处理

$finder = new Finder();
$finder->files()
    ->in('/logs')
    ->name('*.log')
    ->size('> 100K'); // 大于100KB
$results = [];
foreach ($finder as $file) {
    // 读取文件内容
    $content = $file->getContents();
    // 搜索特定内容
    if (str_contains($content, 'ERROR')) {
        $results[] = [
            'file' => $file->getRealPath(),
            'lines' => $this->getErrorLines($content)
        ];
    }
}

性能优化迭代

1 批量处理

class FileBatchProcessor
{
    private $batchSize = 100;
    public function processFiles(Finder $finder, callable $callback): void
    {
        $batch = [];
        $count = 0;
        foreach ($finder as $file) {
            $batch[] = $file;
            $count++;
            // 达到批次大小,处理batch
            if ($count % $this->batchSize === 0) {
                $callback($batch);
                $batch = [];
            }
        }
        // 处理剩余的
        if (!empty($batch)) {
            $callback($batch);
        }
    }
}

2 惰性迭代

// 转换为惰性集合
$files = iterator_to_array($finder);
$collection = new \Doctrine\Common\Collections\ArrayCollection($files);
$collection->map(function ($file) {
    return [
        'path' => $file->getRelativePathname(),
        'size' => $file->getSize(),
        'modified' => $file->getMTime()
    ];
});

多目录迭代

$finder = new Finder();
$finder->files()
    ->in(['/var/www/html', '/var/www/app'])
    ->exclude(['vendor', 'node_modules']);
// 并行处理不同目录
foreach ($finder as $file) {
    $path = $file->getRelativePath();
    switch (true) {
        case str_starts_with($path, 'html/'):
            // 处理 html 目录文件
            break;
        case str_starts_with($path, 'app/'):
            // 处理 app 目录文件
            break;
    }
}

实用示例:文件校验器

class FileValidator
{
    public function validateFiles(string $directory): array
    {
        $finder = new Finder();
        $validator = new FileRulesValidator();
        $finder->files()
            ->in($directory)
            ->name('*.php')
            ->notName('*Test.php');
        $errors = [];
        foreach ($finder as $file) {
            // 逐行检查
            $lines = file($file->getRealPath());
            foreach ($lines as $lineNumber => $line) {
                if (!$validator->validateLine($line)) {
                    $errors[] = [
                        'file' => $file->getRelativePathname(),
                        'line' => $lineNumber + 1,
                        'content' => trim($line)
                    ];
                }
            }
        }
        return $errors;
    }
}

注意事项

  • 性能优化:对于大目录,使用 getIterator() 而不是创建数组
  • 内存管理:迭代过程中确保及时释放不用的文件句柄
  • 异常处理:迭代时捕获异常,避免单个文件问题中断整个流程
foreach ($finder as $file) {
    try {
        // 处理文件
        $content = $file->getContents();
        // 处理逻辑...
    } catch (\Throwable $e) {
        // 记录错误但继续处理其他文件
        Logger::error("处理文件失败: {$file->getRealPath()}", [
            'error' => $e->getMessage()
        ]);
        continue;
    }
}

这样的迭代方式既高效又灵活,能处理各种文件搜索和处理需求。

抱歉,评论功能暂时关闭!