scandir返回的.和..必须手动过滤,因php无内置跳过选项;需用is_file或is_dir判断类型而非仅字符串匹配,并先realpath规范化路径。

scandir 返回的两个特殊目录项必须手动过滤
scandir 默认会返回 .(当前目录)和 ..(父目录),它们不是真实文件或子目录,直接遍历会导致逻辑错误或路径越界。PHP 不提供内置开关跳过它们,必须显式排除。
常见错误是写成 foreach (scandir($path) as $file) { if ($file !== '.' && $file !== '..') { ... } },看似正确,但容易漏掉隐藏文件或误判符号链接。更稳妥的做法是结合 is_file 或 is_dir 进行类型判断,而非仅靠名称匹配。
- 始终用
realpath($path)预处理路径,避免相对路径干扰判断 - 过滤时优先使用
is_file($full_path)而非字符串比较,防止文件名恰好叫.git或..config等边界情况 - 若需区分文件与目录,
scandir本身不递归,别指望它返回完整路径 —— 必须拼接$path . DIRECTORY_SEPARATOR . $file后再判断
只取文件名不取路径:用 array_filter + basename 容易出错
有人习惯先用 scandir 获取全量条目,再对每个条目调用 basename 提取文件名,这在绝大多数情况下多余且低效。因为 scandir 返回的就是纯文件/目录名,不含路径 —— 除非你传入的是类似 /var/www/../logs 这种带 .. 的路径,而这时应该先 realpath 规范化。
真正需要 basename 的场景,是你已经拼出了完整路径(比如 $path.'/'.$file)并想从中提取名字,但那已超出 scandir 的职责范围。
- 直接使用
scandir返回的数组元素就是文件名,无需再basename - 若后续要拼路径,用
dirname($path) . DIRECTORY_SEPARATOR . $file比字符串拼接更安全 - Windows 下
DIRECTORY_SEPARATOR是反斜杠,硬写'/'可能导致is_file失败
性能敏感时别用 scandir 做大量文件过滤
当目录下有上万文件时,scandir 会一次性读取全部元数据到内存,然后你再用 array_filter 遍历判断类型,CPU 和内存开销明显。此时更适合用 DirectoryIterator 或 glob。
glob($path . '/*', GLOB_NOSORT | GLOB_ONLYDIR) 可直接只匹配目录;glob($path . '/*.*') 能按扩展名粗筛,比 scandir + 手动 pathinfo 快得多。但注意 glob 不支持正则,也无法获取文件修改时间等详细信息。
-
scandir适合中小目录( - 如果只要文件名列表且无复杂条件,
array_diff(scandir($path), ['.', '..'])最简,但不判断类型 - 需要同时获取大小、mtime 等信息时,
scandir+stat比反复调用filemtime更高效
中文文件名或特殊字符路径下 scandir 行为不稳定
PHP 5.6+ 在 Linux 下默认以 UTF-8 处理文件名,但 Windows 的 NTFS 使用 UTF-16 编码,而 PHP 的 scandir 在 Windows 上可能返回乱码或截断。这不是函数 bug,而是系统层编码不一致导致的。
典型现象是:目录里有 测试.txt,scandir 返回 ???.txt 或空字符串。此时不能靠 mb_convert_encoding 修复,因为原始字节已损坏。
- Linux 服务器上确保 locale 设置为
en_US.UTF-8或对应中文 locale - Windows 上改用
RecursiveDirectoryIterator,它内部处理了 WinAPI 编码转换 - 绝对避免在路径中混用中文和空格,尤其在 CLI 模式下调用时,shell 层可能提前截断参数
. 和 .. 不够,得确认它真是文件,否则 symlink 指向不存在路径也会让 is_file 返回 false,进而被误剔除。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











