realpath() 返回 false 的常见原因包括路径不存在、任意一级父目录缺少执行权限、符号链接目标不可达、Windows 下大小写不一致导致解析失败,以及 PHAR 等虚拟路径不支持。

realpath() 返回 false 的常见原因
它不是“路径写错了就报错”,而是严格检查路径是否存在、是否可访问。只要 realpath() 中任意一级目录缺少执行(x)权限,或目标文件/目录根本不存在,就直接返回 false。
比如你在 Web 目录下运行:realpath('../config/.env'),但 ../config 目录权限是 750 且不属于当前 PHP 进程用户,函数就会失败——哪怕 .env 文件本身存在且可读。
- 必须确保从当前工作目录到目标路径的**每一层父目录**都对 PHP 进程有执行权限(
chmod +x或等效设置) - 路径中含符号链接时,目标必须可达;相对符号链接(如
../..)容易形成循环或越界,也会导致false - Windows 下不区分大小写,但
realpath()不保证统一转为小写或大写,不能依赖返回值的大小写一致性
realpath() 和 dirname() / basename() 的配合用法
很多人误以为 realpath() 是为了“获取文件名”或“只取目录”,其实它只做一件事:返回规范化的绝对路径字符串。后续拆分得靠其他函数。
例如你传入 './src/../lib/helper.php',realpath() 返回的是类似 '/var/www/project/lib/helper.php' 的完整路径,不会自动帮你截掉文件名。
立即学习“PHP免费学习笔记(深入)”;
- 要取目录部分:用
dirname(realpath($path)),不是dirname($path)—— 后者不解析符号链接 - 要取文件名部分:用
basename(realpath($path)),否则basename('./a/../b.txt')会错误地返回b.txt,而实际目标可能是/var/www/b.txt - 如果路径末尾带斜杠(如
'/var/www//'),realpath()会自动抹掉尾部斜杠,所以不用额外rtrim()
缓存影响和 realpath_cache_* 函数的作用
PHP 默认启用 realpath 缓存,同一路径多次调用 realpath() 不会重复查磁盘——这是性能优化,但也意味着:如果路径在运行期间被外部修改(比如 symlink 被重指向、目录被 mv),缓存不会自动失效。
开发调试时容易因此看到“旧结果”,尤其是 CLI 脚本长期运行或 Web 服务未重启的情况下。
- 查看当前缓存大小:
realpath_cache_size(),单位是字节 - 查看缓存内容(调试用):
realpath_cache_get(),返回一个包含路径映射和过期时间的数组 - 清空缓存(慎用):
clearstatcache(true)—— 注意它清的是整个 stat 缓存,不只是 realpath - 禁用缓存(仅限调试):
ini_set('realpath_cache_size', 0),但上线环境不建议关
替代方案:什么时候不该用 realpath()
如果你只是想拼接路径、不关心目标是否存在,或者需要处理纯虚拟路径(比如 PHAR 包内、S3 URL、SSH 远程路径),realpath() 就不是正确工具。
它无法处理 phar:// 协议路径,对 ssh2_sftp_realpath() 这类远程路径也完全无效——那是另一个函数。
- 拼路径用
__DIR__ . '/sub/file.php'或PATH_SEPARATOR拼接更轻量 - 校验存在性应单独用
file_exists()或is_file(),别依赖realpath()的返回真假来判断 - 处理远程 SFTP 路径必须用
ssh2_sftp_realpath(),它的行为和本地realpath()类似但走 SSH 协议 - PHP 8.1+ 可考虑
PathNormalizer::normalize()(需 symfony/filesystem)做纯字符串规范化,不依赖文件系统
最常被忽略的一点:realpath 的“真实”是操作系统层面的真实路径,不是业务逻辑上的“有效路径”。它解决的是路径解析问题,不是权限控制、存在性兜底或跨协议抽象问题。



















