因为 autoload.php 可能被多个入口文件重复引入,require_once 能确保自动加载器注册逻辑仅执行一次,避免 spl_autoload_register 多次注册同回调报错、全局映射被覆盖或加载顺序错乱。

为什么 autoload.php 里常用 require_once 而不是 require
因为 autoload.php 本身极大概率会被多个入口文件(如 index.php、cli.php、测试启动脚本)重复引入,而它内部又会注册自动加载器(比如调用 spl_autoload_register)。如果用 require,同一份注册逻辑可能被执行多次,导致:
-
spl_autoload_register多次注册相同回调,触发 PHP 警告(Warning: spl_autoload_register(): Function ... is already registered) - 某些自定义加载器逻辑(如全局映射数组初始化)被重复执行,造成覆盖或冲突
- 加载器执行顺序错乱,尤其在多个
autoload.php共存的遗留项目中
require_once 保证该文件只被解析执行一次,是防御性写法,不依赖开发者记住“谁已经引过了”。
注意:require_once 的“一次”是按文件路径判定的,所以:
- 使用
__DIR__ . '/autoload.php'比'./autoload.php'更可靠,避免因工作目录不同导致重复加载 - OPcache 启用时,
require_once的文件级去重仍有效,无需额外干预
spl_autoload_register 本身是否幂等?
不是。多次调用 spl_autoload_register 注册同一个匿名函数或可调用对象,PHP 会明确报错:
Warning: spl_autoload_register(): Function ... is already registered
即使你用的是类方法(如 [MyLoader::class, 'load']),只要该回调已注册过,再次注册就会失败。
所以常见写法是:
- 在
autoload.php开头加if (function_exists('spl_autoload_register')) { ... }无意义——函数肯定存在,问题在注册行为本身 - 真正要防的是文件被重复包含,而不是函数是否存在
- 更健壮的做法:把注册逻辑封装进一个函数,首次调用才注册,但前提是这个函数不会被多次 require —— 回到原点,还是得靠
require_once
什么时候可以放心用 require?
仅当你能 100% 确保该文件在整个请求生命周期中只被一个入口点引入一次,例如:
- 项目只有一个统一入口(如 Laravel 的
public/index.php),且所有 CLI/Worker 脚本都复用它 -
autoload.php被写死在 Composer 生成的vendor/autoload.php中,而你从不手动 require 它(Composer 自己用require_once)
但现实中,很多团队会为测试、部署钩子、定时任务单独写启动脚本,直接 require 'autoload.php'。这时候不用 require_once,第一周可能没事,第三周就突然报 autoload 重复注册。
现代项目里,autoload.php 还需要手写吗?
绝大多数不需要。Composer 自动生成的 vendor/autoload.php 已经用 require_once 包裹了全部逻辑,并做了路径标准化和注册保护。
如果你还在维护一个手写的 autoload.php,重点不是纠结 require 还是 require_once,而是检查它是否还绕过了 Composer —— 那才是更隐蔽的风险点。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











