recursivedirectoryiterator 必须与 recursiveiteratoriterator 配合才能递归遍历子目录,单独使用只返回根节点;需显式传 filesystemiterator::skip_dots 等 flag,并用 try/catch 处理 permission denied 异常,结合 callbackfilteriterator 可高效筛选 .php 文件。

RecursiveDirectoryIterator 不是“开箱即用”的神器,它必须和 RecursiveIteratorIterator 配合才能真正遍历子目录——单独 new 一个,foreach 什么也吐不出来。
为什么直接 foreach RecursiveDirectoryIterator 没输出?
因为 RecursiveDirectoryIterator 本身只代表一棵树的“根节点”,它不会自动展开子目录。它返回的是嵌套结构,不是线性列表。
常见现象:写了 foreach (new RecursiveDirectoryIterator($path) as $item),结果只看到第一层目录项,甚至什么都没打印。
- 必须包一层
RecursiveIteratorIterator才能“压平”层级 - 构造
RecursiveIteratorIterator时传RecursiveIteratorIterator::LEAVES_ONLY,才能只拿到文件(跳过空目录) - 若传
RecursiveIteratorIterator::SELF_FIRST,会先吐目录本身,再吐其内容,需额外判断$item->isFile()
RecursiveDirectoryIterator 构造时要传哪些 flag?
默认行为不够明确,容易漏掉点文件或踩权限坑。
- 显式传
FilesystemIterator::SKIP_DOTS,比依赖默认更可靠——确保自动跳过.和.. - 不传
FilesystemIterator::FOLLOW_SYMLINKS,软链接会被当普通文件处理(不进入);如需跟随,得加这个 flag 并注意设最大深度防环 - 避免用
0或空 flag,否则在某些 PHP 版本下可能触发意外行为(比如返回相对路径而非完整路径)
遍历时遇到 Permission denied 怎么办?
不是 warning,是 UnexpectedValueException,不捕获就会中断整个遍历。
- 必须用
try/catch包裹foreach循环体,不能只包外层 new - catch 到
UnexpectedValueException后,continue即可跳过当前不可读目录,继续下一个条目 - 不要用
@抑制错误——它对迭代器内部抛出的异常无效 - 如果想记录被跳过的路径,可在 catch 块里写
error_log("Skip unreadable: " . $e->getMessage())
怎么只取 .php 文件?别用 glob,用 FilterIterator
用 glob('**/*.php') 看似简单,但 PHP 7.4 的 ** 支持不稳定,且无法动态控制、不返回元信息。
- 推荐组合
CallbackFilterIterator:在迭代器链里加一层过滤逻辑 - 示例:
new CallbackFilterIterator($iterator, fn($item) => $item->isFile() && pathinfo($item->getFilename(), PATHINFO_EXTENSION) === 'php') - 这样既保持惰性迭代(内存友好),又能复用
SplFileInfo方法查大小、修改时间等 - 如果正则匹配更灵活,换
RegexIterator,但注意它的$mode参数(如RegexIterator::MATCH)必须显式指定
RecursiveDirectoryIterator 的关键不在“递归”二字,而在它返回的是 SplFileInfo 对象——这意味着你不用再 stat()、不用 pathinfo() 二次解析,但前提是别忘了它默认静默跳过不可读目录,也别指望它自己展开树。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











