glob() 返回匹配路径的索引数组,失败时返回 false 而非空数组;直接 foreach 或传给 json_decode() 会报错,需先用 === false 判断,大目录应改用 DirectoryIterator。

glob() 不是“遍历目录”的替代品,而是“一次性匹配路径列表”的工具——它返回数组,不是资源句柄,不能边读边处理;用错场景或误判返回值类型,八成会报 Warning: Invalid argument supplied for foreach() 或 Argument #1 must be of type string, array given。
glob() 返回值到底是啥?为什么 foreach 会报错
它返回的是一个 array(匹配到的完整路径字符串组成的索引数组),匹配失败时返回 false,不是空数组。这是最常踩的坑:
- 直接对
glob()结果做foreach前,必须先检查是否为false,否则当目录不存在或无权限时,foreach(false)就崩了 - 绝不能把结果传给
json_decode()——它根本不是 JSON 字符串,有人从日志里复制了输出就硬解,立马报Argument #1 must be of type string, array given -
glob('path/*')匹配的是path/file1.txt、path/subdir/这样的完整路径,不是纯文件名;要取名字得用basename($file)
只列文件夹?必须加 GLOB_ONLYDIR 标志
想列出 uploads/ 下所有子目录,写成 glob('uploads/') 是错的——它只匹配 uploads/ 自身;写成 glob('uploads/*') 又会混入文件。正确写法:
$dirs = glob('uploads/*', GLOB_ONLYDIR);
if ($dirs === false) {
echo "无法读取 uploads 目录";
} else {
foreach ($dirs as $dir) {
echo basename($dir) . "\n"; // 输出:2026-08, temp, archive
}
}
-
GLOB_ONLYDIR是关键,它过滤掉所有非目录项(Windows/macOS/Linux 均支持) - 路径末尾不加斜杠不影响匹配,但加了
uploads/*/更语义清晰,部分旧系统更稳定 - 如果目录里有隐藏文件夹(如
.git),默认不会被匹配;需要显式加GLOB_HIDDEN标志
匹配多种后缀?小心 GLOB_BRACE 的兼容性
想同时找 .php 和 .inc 文件,写 glob('src/*.{php,inc}', GLOB_BRACE) 很简洁,但要注意:
立即学习“PHP免费学习笔记(深入)”;
-
GLOB_BRACE在 Windows 上 PHP 8.0+ 才完全可靠;PHP 7.x 在某些 Windows 环境下会静默失效,返回空数组 - 更稳妥的跨平台写法是两次调用 +
array_merge():array_merge(glob('src/*.php'), glob('src/*.inc')) - 通配符
*不会匹配以点开头的文件(如.env),要包含它们,必须加GLOB_HIDDEN - 大目录下慎用复杂模式(如
**/*.php)——glob()本身不支持双星号递归,那是 shell 扩展,PHP 不认
第 N 个匹配项怎么取?别循环,直接用数组下标
要取“第 5 个 PDF 文件”,不用 foreach 计数,glob() 返回的就是标准索引数组:
$pdfs = glob('docs/*.pdf');
if (isset($pdfs[4])) { // 第 5 个 → 下标 4
$fifth = $pdfs[4];
echo "第五个 PDF:" . basename($fifth);
} else {
echo "总共只有 " . count($pdfs) . " 个 PDF";
}
- 务必用
isset($arr[$n])判断,不要只靠count()后再访问——避免未定义索引警告 - 若目录含数十万文件,
glob()会一次性加载全部路径到内存,可能 OOM;此时应换DirectoryIterator流式读取 + 手动计数 - 排序是默认行为(按字典序),如需按修改时间排序,得先获取全部路径,再用
usort()+filemtime()重排
真正容易被忽略的点:glob() 的 pattern 是由底层 libc 或 Windows API 解析的,不是 PHP 自己实现的通配逻辑。这意味着路径中出现中文、emoji 或特殊符号(如 [、{)时,不同系统表现可能不一致;生产环境建议路径保持 ASCII,文件名用 URL 编码或 base64 存储更稳妥。



















