__autoload() 是 PHP 5 引入的魔术函数,在实例化未定义类时自动触发。虽已被 spl_autoload_register() 取代并最终在 PHP 8.0 移除,但理解其原理有助于掌握现代自动加载机制。本文解析两种经典实现模式及现代最佳实践。
<?php
function __autoload($classname) {
// 控制器类:以 Action 结尾
if (substr($classname, -6) === "Action") {
include APP_PATH . 'controllers/' . $classname . '.class.php';
}
// 模型类:以 Model 结尾
elseif (substr($classname, -5) === "Model") {
include APP_PATH . 'models/' . $classname . '.class.php';
}
// Smarty 模板引擎
elseif ($classname === "Smarty") {
include SYSTEM_PATH . 'smarty/Smarty.class.php';
}
// 通用类库
else {
include APP_PATH . 'common/' . $classname . '.class.php';
}
}
?>
适用场景:早期 MVC 框架(如 ThinkPHP 1.x/2.x),约定优于配置。
<?php
function __autoload($class_name) {
// 将类名中的下划线转为目录分隔符
$path = str_replace('_', DIRECTORY_SEPARATOR, $class_name);
require_once $path . '.php';
}
?>
示例:Zend_Db_Adapter_Mysql → Zend/Db/Adapter/Mysql.php
优势:跨平台兼容(DIRECTORY_SEPARATOR),符合 PEAR/Zend 命名规范。
<?php
// 注册多个加载器,按顺序尝试
spl_autoload_register(function ($class) {
// 项目类加载器
$file = __DIR__ . '/src/' . str_replace('\\', '/', $class) . '.php';
if (file_exists($file)) {
require $file;
return true;
}
});
spl_autoload_register(function ($class) {
// 第三方库加载器(vendor 目录)
$file = __DIR__ . '/vendor/' . str_replace('\\', '/', $class) . '.php';
if (file_exists($file)) {
require $file;
return true;
}
});
// 自定义异常处理
spl_autoload_register(function ($class) {
throw new Exception("Class $class not found");
}, true, true); // prepend=true, throw=true
现代 PHP 项目标准配置:
{
"autoload": {
"psr-4": {
"App\\": "src/",
"Vendor\\Package\\": "packages/package/src/"
},
"files": ["src/helpers.php"] // 全局函数文件
}
}
src/
├── Controller/
│ └── UserController.php // namespace App\Controller; class UserController
├── Model/
│ └── User.php // namespace App\Model; class User
└── helpers.php // 全局函数
require_once __DIR__ . '/vendor/autoload.php';
生产环境执行 composer dump-autoload -o 生成 classmap,将命名空间到文件路径的映射缓存为数组,避免文件系统 stat 调用,提升 20-30% 加载速度。
| 遗留代码 | 现代替代 |
|---|---|
__autoload | spl_autoload_register 或 Composer |
下划线命名 Zend_Db | 命名空间 Zend\Db |
手动 include 路径拼接 | PSR-4 标准目录结构 |
require_once 重复检查 | Composer 类映射去重 |