PHP 自動載入 (Autoloading)
自動載入讓 PHP 在需要類別時自動載入對應的檔案,不需要手動 require 每個檔案。在沒有自動載入的情況下,你必須在使用每個類別之前手動 require 或 include 它的檔案,這在大型專案中會變得非常繁瑣且容易出錯。
spl_autoload_register
spl_autoload_register() 函數讓你註冊一個自動載入函數。當 PHP 遇到一個未定義的類別時,會呼叫這個函數,並傳入類別名稱作為參數。你的函數負責找到並載入對應的檔案:
<?php
spl_autoload_register(function (string $class) {
$file = __DIR__ . '/src/' . str_replace('\\', '/', $class) . '.php';
if (file_exists($file)) {
require $file;
}
});
// 現在可以直接使用類別
$user = new App\Models\User("Alice");
?>
PSR-4 自動載入
PSR-4 是 PHP-FIG(PHP Framework Interoperability Group)制定的自動載入標準。它定義了命名空間與檔案路徑之間的對應規則,讓不同的套件和框架可以無縫地一起運作:
| 完整類別名稱 | 命名空間前綴 | 基礎目錄 | 檔案路徑 |
|---|---|---|---|
| App\Models\User | App\ | src/ | src/Models/User.php |
| App\Controllers\HomeController | App\ | src/ | src/Controllers/HomeController.php |
簡單的 PSR-4 載入器
<?php
class Autoloader {
private array $prefixes = [];
public function register(): void {
spl_autoload_register([$this, 'loadClass']);
}
public function addNamespace(string $prefix, string $baseDir): void {
$prefix = trim($prefix, '\\') . '\\';
$baseDir = rtrim($baseDir, '/') . '/';
$this->prefixes[$prefix] = $baseDir;
}
public function loadClass(string $class): void {
foreach ($this->prefixes as $prefix => $baseDir) {
if (strpos($class, $prefix) === 0) {
$relativeClass = substr($class, strlen($prefix));
$file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';
if (file_exists($file)) {
require $file;
return;
}
}
}
}
}
$loader = new Autoloader();
$loader->addNamespace('App\\', __DIR__ . '/src/');
$loader->register();
?>
使用 Composer
Composer 是 PHP 的標準套件管理工具,也提供強大的自動載入功能。在實際專案中,幾乎都會使用 Composer 來處理自動載入,而非自己實作。
composer.json
{
"name": "myapp/project",
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
使用
# 產生自動載入檔案
composer dump-autoload
<?php
// 只需要載入一次
require __DIR__ . '/vendor/autoload.php';
// 自動載入所有類別
use App\Models\User;
use App\Services\UserService;
$user = new User("Alice");
?>
目錄結構範例
project/
├── composer.json
├── vendor/
│ └── autoload.php
├── src/
│ ├── Models/
│ │ └── User.php
│ ├── Controllers/
│ │ └── UserController.php
│ └── Services/
│ └── UserService.php
└── public/
└── index.php
src/Models/User.php
<?php
namespace App\Models;
class User {
public function __construct(
public string $name,
public string $email
) {}
}
?>
public/index.php
<?php
require __DIR__ . '/../vendor/autoload.php';
use App\Models\User;
$user = new User("Alice", "alice@example.com");
echo $user->name;
?>
多重命名空間
{
"autoload": {
"psr-4": {
"App\\": "src/",
"Tests\\": "tests/"
},
"files": [
"src/helpers.php"
],
"classmap": [
"legacy/"
]
}
}
最佳實踐
- 使用 Composer - 標準化的自動載入
- 遵循 PSR-4 - 命名空間對應目錄結構
- 一個檔案一個類別 - 便於自動載入
- 類別名稱與檔案名稱相符 - User.php 包含 User 類別