stopOnVCSIgnored 是 Symfony Finder ≥6.2 引入的目录级剪枝方法,需先调用 ignoreVCSIgnored(true) 才生效,遇含 .gitignore 的目录即终止递归,提升大规模项目扫描性能。

stopOnVCSIgnored 是 Symfony Finder 组件 自 6.2 版本起引入 的一个方法(注意:Symfony 8.0 默认捆绑的是 Finder v6.4+),用于控制 Finder 在遍历目录时,是否在遇到 .gitignore(或其他 VCS ignore 文件)所在目录时停止向下递归。它不是“跳过被忽略的文件”,而是提前终止对整个子树的扫描,从而提升大规模项目中的查找性能。
这个方法仅在启用 .gitignore 支持的前提下生效,且需配合 ignoreVCSIgnored(true) 使用。
✅ 正确使用前提
- 你使用的是 Finder ≥ 6.2(Symfony 8.0 满足)
- 已启用
.gitignore解析(默认不启用,需显式开启) -
stopOnVCSIgnored(true)必须在ignoreVCSIgnored(true)之后调用才有效
use Symfony\Component\Finder\Finder;
$finder = Finder::create()
->in(__DIR__.'/src')
->ignoreVCSIgnored(true) // ? 必须先启用 .gitignore 解析
->stopOnVCSIgnored(true); // ? 遇到含 .gitignore 的目录即停止递归此时,若 __DIR__.'/src/Tests' 下存在 .gitignore,Finder 将完全跳过 Tests/ 及其所有子目录(哪怕里面还有匹配的 PHP 文件)。
⚠️ 常见误区与说明
-
stopOnVCSIgnored(true)不等于 “跳过被.gitignore匹配的文件”
→ 它是目录级剪枝(pruning),不是文件级过滤。被忽略的文件仍可能被上层目录中其他规则匹配到(如果未被剪枝)。 - 若某目录没有
.gitignore,但其父目录有,Finder 不会回溯停止;只在当前目录存在.gitignore时触发停止。 - 它目前只识别
.gitignore(不支持.hgignore或.svnignore)。 - 该行为不影响
exclude()、notName()等其他过滤逻辑,仅作用于递归路径遍历阶段。
? 实际效果对比示例
假设目录结构如下:
project/ ├── .gitignore # 内容:/vendor/\n/tests/ ├── src/ │ ├── Command/ │ └── Tests/ # ← 这里也会被自动创建 .gitignore?不,实际只看项目根下的 .gitignore ├── tests/ # ← 根目录下有 /tests/ 被 ignore,且该目录存在 └── vendor/
执行以下代码:
$finder = Finder::create()
->files()
->name('*.php')
->in(__DIR__)
->ignoreVCSIgnored(true)
->stopOnVCSIgnored(true);Finder 将:
- 扫描
project/下所有子目录; - 进入
tests/前,发现根目录.gitignore中声明了/tests/→ 直接跳过整个tests/目录及其子目录; - 同样跳过
vendor/(因/vendor/被 ignore); - 继续扫描
src/、bin/等未被 ignore 的目录。
? 提示:这对 CI 场景或静态分析工具(如 PHPStan、PHP-CS-Fixer)提速明显,避免无谓遍历
tests/或var/。
? 补充:如何确认是否生效?
可结合 getIterator() + 调试输出路径来验证:
foreach ($finder as $file) {
echo $file->getPathname() . "\n";
}若 tests/SomeTest.php 未出现在输出中,且你已启用 stopOnVCSIgnored(true),基本说明剪枝成功。
不复杂但容易忽略。


















