php mkdir递归创建目录的正确写法是调用mkdir($path, $mode, true),自php 5.0.0起原生支持内建递归逻辑;若遗漏第三个参数$recursive=true,当父目录不存在时会报“no such file or directory”错误。

PHP mkdir递归创建目录的正确写法
直接用 mkdir() 第二个参数传 true 就行,不用自己手写循环或判断。这是 PHP 5.0+ 原生支持的特性,不是“模拟递归”,而是内建递归逻辑。
常见错误是只传路径和权限,却漏掉第三个参数($recursive),结果报 Warning: mkdir(): No such file or directory —— 因为父目录不存在时默认不创建。
-
mkdir('/var/log/app/cache', 0755, true):成功创建多级路径 -
mkdir('/var/log/app/cache')(无第三参数):如果/var/log/app不存在,直接失败 - 权限
0755是八进制,必须带前导0;写成755会被当十进制处理,实际权限变成113(完全不可用)
为什么有时 mkdir(true) 还是失败?
根本原因通常是上层目录权限不足,或 Web 服务器用户(如 www-data、nginx)对父路径没有写权限,而不是函数本身问题。
比如 /var/log 默认只有 root 可写,PHP 进程无法在其中创建子目录,此时 mkdir() 会静默失败(返回 false),但不会提示具体哪一级没权限。
- 用
is_writable(dirname($path))逐级检查最靠近的可写父目录 - Linux 下执行
ls -ld /var /var/log看实际权限和属主 - 避免硬编码绝对路径;开发环境用
__DIR__ . '/storage/cache'更安全
mkdir(true) 的兼容性与性能注意点
PHP 5.0.0 起支持 $recursive = true,但早期版本(如 5.0.0–5.1.6)存在 umask 干扰问题:即使传了 0755,最终目录权限可能被系统 umask 截断(比如变成 0700)。PHP 5.2.5+ 已修复。
性能上无需担心:内核级递归比 PHP 层 while 循环快得多,且只做必要路径检查,不会重复 stat。
- 生产环境建议加判断:
if (!is_dir($path) && !mkdir($path, 0755, true)) { throw new RuntimeException("Failed to create directory: $path"); } - Windows 下路径分隔符用
/或\都行,mkdir()内部自动 normalize - 不要依赖
clearstatcache()来“刷新”目录是否存在 ——is_dir()结果不准通常是因为权限或 race condition,不是缓存问题
替代方案:什么时候不该用 mkdir(true)
当需要精细控制每级目录的权限(比如父目录 0755,子目录 0700),或需在某级创建后执行额外操作(如 chown、记录日志),就不能靠单次 mkdir(true) 完成。
此时应手动拆解路径,用 dirname() 和 basename() 逐级创建,并对每一级单独调用 mkdir() + chmod()。
- 示例路径拆解:
$parts = explode('/', ltrim($path, '/'));,再 foreach 拼接并创建 - 注意空字符串过滤:
array_filter($parts),避免根路径//导致异常 - 更稳妥的做法是用 Composer 包
symfony/filesystem的mkdir()方法,它封装了跨平台和权限回退逻辑
ls -l 看父目录是谁、能不能写。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











