自動載入讓 PHP 在使用類別時才引入檔案,避免一次 include 所有類別檔,實現 Lazy Loading。本文從魔術方法 __autoload 演進到 spl_autoload_register、PSR-4 標準與 Composer 整合,建立現代化專案架構。
| 階段 | 機制 | 特點 |
|---|---|---|
| PHP 5 早期 | __autoload($class) | 全域單一函式,無法共存多個載入器 |
| PHP 5.1.2+ | spl_autoload_register() | 支援多載入器堆疊、例外處理、優先順序 |
| PHP-FIG 制定 | PSR-0 / PSR-4 | 命名空間對應目錄結構的業界標準 |
| 現代專案 | Composer 自動產生 | 零配置、支援版本鎖定、最佳化 Class Map |
<?php
// 定義命名空間前綴對應的基礎目錄
$prefixDirs = [
'App\\' => __DIR__ . '/app',
'Lib\\' => __DIR__ . '/lib',
'Vendor\\' => __DIR__ . '/vendor',
];
spl_autoload_register(function ($class) use ($prefixDirs) {
foreach ($prefixDirs as $prefix => $baseDir) {
$len = strlen($prefix);
if (strncmp($class, $prefix, $len) !== 0) continue;
$relativeClass = substr($class, $len);
$file = $baseDir . '/' . str_replace('\\', '/', $relativeClass) . '.php';
if (file_exists($file)) {
require $file;
return;
}
}
});
// 使用範例
$user = new App\Models\User(); // 自動載入 app/Models/User.php
class Autoload {
protected static $_instance = null;
public static function instance() {
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public static function register() {
spl_autoload_register([self::instance(), 'autoload']);
}
public function autoload($class) {
if (!is_string($class)) return;
// 將命名空間分隔符轉為目錄分隔符,並處理底線分隔單字
$classFile = str_replace('_', DIRECTORY_SEPARATOR, ucwords(str_replace('_', ' ', $class)));
$classFile .= '.php';
if (file_exists($classFile)) {
include $classFile;
}
}
}
// 註冊
Autoload::register();
// composer.json
{
"autoload": {
"psr-4": {
"App\\": "app/",
"Lib\\": "lib/"
}
}
}
// 執行
composer dump-autoload -o
// 專案入口只需一行
require __DIR__ . '/vendor/autoload.php';
Composer 會自動產生最佳化的 Class Map,效能最佳且零維護成本,強烈建議所有專案採用。
false 讓下一個載入器繼續嘗試。-o 最佳化參數產生 Class Map,減少檔案系統 I/O。