require是立即同步加载文件的语句,autoload是类未定义时触发的延迟加载机制;前者执行任意PHP代码,后者仅确保类可用;__autoload已废弃,必须用spl_autoload_register注册。

require 是文件加载指令,autoload 是类加载机制
require 是 PHP 的语言级语句,作用是**立即读取并执行指定路径的 PHP 文件**,不管里面有没有类、函数或变量。它不关心内容结构,只管“把这段代码拉进来运行”。而 autoload(准确说是自动加载机制)是 PHP 在**尝试使用一个尚未定义的类时**,才触发的延迟加载行为,目标明确:只为让那个类可用。
常见错误现象包括:误以为 require 'User.php' 和 new User() 效果一样——其实前者只是执行文件,后者才真正触发 autoload;或者在 require 之后仍报 Class 'User' not found,说明文件里压根没定义 User 类,或者定义了但命名空间/类名不匹配。
-
require发生在你写代码的位置,同步、强制、无条件 - autoload 发生在
new、static::、instanceof等首次引用类的地方,异步、按需、可中断 -
require路径错 → 致命错误(Fatal error: require(): Failed opening required) - autoload 找不到类 → 仍是致命错误(
Fatal error: Class 'X' not found),但错误源头在类引用处,不是在 autoload 函数里
__autoload 已失效,spl_autoload_register 是唯一可行路径
如果你看到老项目里还用着 function __autoload($class) { ... },请立刻停用。PHP 7.2 起已标记为 DEPRECATED,PHP 8.0 彻底移除。现在所有有效 autoload 都必须通过 spl_autoload_register() 注册。
关键差异在于注册方式和容错能力:
立即学习“PHP免费学习笔记(深入)”;
- 只能有一个
__autoload,多人协作或引入第三方库时必然冲突 -
spl_autoload_register()可多次调用,每个回调独立执行,顺序触发,失败也不阻断后续加载器 - 你可以用匿名函数、静态方法、对象方法注册,甚至加
prepend=true控制优先级 - 加载失败时,
spl_autoload_register回调里可以throw自定义异常,而__autoload里die()会直接终止脚本
require_once 和 spl_autoload_register 都防重复,但防的是不同东西
require_once 防的是**同一个文件被多次包含**,靠的是内部文件路径哈希表;spl_autoload_register 防的是**同一个类被多次加载**,靠的是 PHP 内核在类定义后自动跳过后续 autoload 尝试。
这意味着:即使你写了两个不同的 autoload 回调,都试图加载 App\User,第二个根本不会被执行——内核发现类已存在,连回调都不会进。但如果你手动 require_once 'User.php',再 new User(),autoload 还是会被触发(除非你提前 class_exists('User') 检查并跳过)。
- 别指望 autoload 替代
require_once去防文件重复包含 - 也别在 autoload 回调里再套一层
require_once——require就够了,autoload 本身已保证单次加载 - 如果类文件里有全局副作用(比如注册函数、改配置),注意 autoload 的触发时机不可控,可能比你预期早
实际项目中它们经常共存,但职责绝不重叠
现代 PHP 项目典型结构是:vendor/autoload.php(Composer 生成,基于 spl_autoload_register)负责所有类;而 config/database.php、bootstrap.php 这类非类文件,依然靠 require 或 require_once 显式加载。
容易踩的坑:
- 在 autoload 回调里用
require 'config.php'—— 配置不该随类加载而加载,会导致多次执行或顺序混乱 - 把
require写在类定义前却忘了命名空间,导致 autoload 按完整类名找文件失败(例如App\Models\User对应src/App/Models/User.php,不是src/User.php) - 用
require加载了一个类文件,但该文件里用了namespace App;却没写class User,结果new User()仍报错,因为类名不匹配
最常被忽略的一点:autoload 只响应类,不响应接口、trait、函数或常量。你要加载这些,还是得回到 require。



















