PHP 5 引入 __autoload() 魔術方法,嘗試解決「手動 require 類別檔案」的痛點。雖已被 spl_autoload_register() 取代(PHP 7.2 棄用,PHP 8.0 移除),理解其運作機制有助於掌握現代自動載入器(Composer PSR-4)的核心邏輯。
當程式碼使用尚未定義的類別時(new ClassName()、ClassName::method()、extends ClassName、implements Interface、instanceof ClassName、type-hint),PHP 會自動呼叫 __autoload(string $className),給予一次載入機會。
<?php
// 定義自動載入器
function __autoload($className) {
$file = __DIR__ . '/classes/' . $className . '.class.php';
if (file_exists($file)) {
require_once $file;
}
}
// 使用類別(未 require)
$user = new User(); // 觸發 __autoload('User') → 載入 classes/User.class.php
$order = new Order(); // 觸發 __autoload('Order')
?>
這是原文強調的重點。__autoload 機制在 require_once 載入檔案後,只檢查該類別是否已定義。若檔案包含類別定義以外的程式碼(全域變數、常數、函數、執行邏輯),不會被執行。
<?php
// Test.class.php
$publicPara = '中共十七大啥時候召開的?'; // 全域變數
class Test {
public function __construct() {
global $publicPara;
echo isset($publicPara) ? $publicPara : "管我啥事兒了?";
}
}
// do.php - 手動 require(正常執行)
require_once 'Test.class.php';
new Test(); // 輸出:中共十七大啥時候召開的?
// autoload.php - 使用 __autoload
function __autoload($className) {
require_once $className . '.class.php';
}
new Test(); // 輸出:管我啥事兒了? ← $publicPara 未被執行!
?>
Test.class.php 時,發現類別定義 class Test,將其加入類別表。$publicPara 屬於「腳本執行階段」程式碼,非類別定義一部分。__autoload 機制只關心「類別是否已可用」,一旦 class Test 存在,即視為載入成功,不保證執行檔案中所有語句。require_once 仍會執行整個檔案,但 global $publicPara 在類別方法中引用時,若全域作用域未定義該變數,則為 null。<?php
// 正確:Test.class.php 只包含類別定義
namespace App\Models;
class Test {
public const DEFAULT_PARA = '中共十七大啥時候召開的?'; // 類別常數
public function __construct() {
echo self::DEFAULT_PARA;
}
}
// 若需共用設定,使用獨立設定檔或 Dependency Injection
// config.php
return ['public_para' => '...'];
// 類別中注入
class Test {
public function __construct(private string $param) {}
}
$test = new Test(config('public_para'));
?>
__autoload 只能定義一個,無法組合多個載入器(如專案本體 + 第三方套件)。spl_autoload_register() 支援多載入器堆疊。
<?php
// 專案自動載入器(PSR-4 簡易實作)
spl_autoload_register(function ($class) {
$prefix = 'App\\';
$baseDir = __DIR__ . '/src/';
if (strncmp($class, $prefix, strlen($prefix)) !== 0) return;
$relativeClass = substr($class, strlen($prefix));
$file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';
if (file_exists($file)) {
require_once $file;
}
});
// Composer 自動載入(生產環境標準)
require_once __DIR__ . '/vendor/autoload.php';
// 即可使用所有符合 PSR-4 的套件類別
?>
| 操作 | 是否觸發 | 備註 |
|---|---|---|
new ClassName() | ✅ | 實例化 |
ClassName::staticMethod() | ✅ | 靜態方法呼叫 |
ClassName::CONSTANT | ✅ | 類別常數存取 |
extends ClassName | ✅ | 繼承 |
implements InterfaceName | ✅ | 實作介面 |
instanceof ClassName | ✅ | 型別檢查 |
function foo(ClassName $x) | ✅ | 型別提示(執行時檢查) |
class_exists('ClassName') | ✅ | 預設 $autoload=true |
interface_exists() | ✅ | |
trait_exists() | ✅ |
User.php vs user.php。PSR-4 規範類別名稱 StudlyCaps、檔名同類別名。App\Models\User 應對應 src/Models/User.php。file_exists 檢查慢。Composer 產生 classmap 或 PSR-4 映射表 直接定位檔案。__autoload 是 PHP 自動載入的雛形,核心機制是「類別首次使用時嘗試載入」。其關鍵限制是不保證執行類別檔案中的非類別程式碼,因此類別檔案應純粹只定義類別。現代專案請使用 Composer + PSR-4,享受標準化、高效能、可組合的自動載入體驗。