glob() 并不比 opendir() 更快,反而在多数场景下更慢,尤其文件量大或通配复杂时;它因代码简洁被误认为高效,实则需解析模式、逐文件匹配、拼接路径,开销更大。

glob() 并不比 opendir() 效率更高——相反,绝大多数场景下它更慢,尤其在文件量大或通配逻辑复杂时。
glob() 为什么常被误认为“更快”
很多人看到 glob('*.php') 一行代码就拿到结果,而 opendir()+readdir() 要写循环、过滤、关闭句柄,就主观觉得 glob() “更高效”。
但实际是:简洁 ≠ 快。glob() 内部仍调用系统级目录遍历(类似 opendir),但它额外做了三件事:
- 解析 glob 模式(比如把
*.php编译成匹配规则) - 对每个文件名执行字符串比对或正则模拟(即使简单后缀也非直接 memcmp)
- 返回完整路径数组,意味着内存分配 + 字符串拼接开销
数千文件时,glob() 比纯 opendir() 慢 3–5 倍是常见现象。
scandir() 才是真正兼顾简洁与性能的选择
scandir() 是 PHP 层最轻量的目录读取方式:
- 直接调用系统
readdir(),无模式解析开销 - 返回纯文件名数组(不含路径),内存友好
- 支持排序参数(
SCANDIR_SORT_NONE可避免默认 ASCII 排序)
实操建议:
- 只要不需要通配,直接用
scandir($path),再用array_filter()筛选,比如:$files = array_filter(scandir($path), function($f) { return $f !== '.' && $f !== '..' && strtolower(pathinfo($f, PATHINFO_EXTENSION)) === 'php'; }); - 若需排除
.和..,优先用array_diff(scandir($path), ['.', '..']),比循环判断快 - PHP 8.1+ 的
StreamWrapper缓存目录列表不可靠——每次opendir()都是新句柄,缓存极易过期或返回脏数据
glob() 唯一适合的场景:简单通配且文件极少
glob() 不该用于性能敏感路径,但某些低频、小规模、强可读性需求下仍有价值:
- 临时脚本快速查几个配置文件:
glob('/etc/*.conf') - CI/CD 中扫描固定命名的构建产物:
glob('dist/*.js') - 你明确知道目录下最多几十个文件,且不愿写过滤逻辑
注意这些坑:
-
glob('*.php')在当前目录工作,glob('/path/*.php')才带路径——别混淆作用域 - 它不递归;要扫子目录得用
GLOB_BRACE或glob('**/*.php', GLOB_BRACE)(PHP 7.4+),但性能断崖下跌 - 遇到特殊字符(如空格、括号)可能意外失败,
scandir()+ 手动fnmatch()更可控
真正影响性能的不是函数名,而是你是否让 PHP 多做了一次遍历、一次字符串处理、一次路径拼接。scandir() 给你原始数据,glob() 替你做决定——而那个决定,往往比你手动 filter 还慢。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











