以雙底線 __ 開頭的特殊方法,PHP 在特定時機自動呼叫,無需手動調用,賦予物件「魔術」行為。
| 方法 | 觸發時機 | 參數 | 回傳值要求 | 典型用途 |
|---|---|---|---|---|
__construct() | 實例化物件時 | 任意 | 無 | 初始化屬性、資源連線 |
__destruct() | 物件銷毀時(腳本結束/unset) | 無 | 無 | 釋放資源、關閉連線、寫入日誌 |
__call($name, $args) | 呼叫不存在的實例方法 | $name: 方法名 $args: 參數陣列 | 任意 | 動態方法代理、API 客戶端 |
__callStatic($name, $args) | 呼叫不存在的靜態方法 | $name: 方法名 $args: 參數陣列 | 任意 | 靜態工廠、動態查詢建構 |
__get($name) | 讀取不可存取屬性時 | $name: 屬性名 | 屬性值 | 虛擬屬性、延遲載入、資料轉換 |
__set($name, $value) | 寫入不可存取屬性時 | $name: 屬性名 $value: 值 | 無 | 資料驗證、自動轉換、觸發事件 |
__isset($name) | 對不可存取屬性呼叫 isset()/empty() | $name: 屬性名 | bool | 虛擬屬性存在性檢查 |
__unset($name) | 對不可存取屬性呼叫 unset() | $name: 屬性名 | 無 | 清理虛擬屬性、快取失效 |
__toString() | 物件當作字串使用時 | 無 | 必須回傳字串 | 物件字串表示、除錯輸出 |
__invoke() | 物件當作函數呼叫時 | 任意 | 任意 | 可呼叫物件、閉包替代、策略模式 |
__clone() | 物件被 clone 關鍵字複製時 | 無 | 無 | 深度複製、重置識別碼、複製資源 |
__sleep() | serialize() 序列化前 | 無 | 陣列:屬性名列表 | 排除資源連線、壓縮大型資料 |
__wakeup() | unserialize() 反序列化後 | 無 | 無 | 重建資源連線、初始化狀態 |
__set_state($arr) | var_export() 匯出時 | $arr: 屬性陣列 | 物件實例 | 自定義匯出格式、單例模式支援 |
__autoload($class) | 實例化不存在類別時 (已棄用) | $class: 類別名 | 無 | 自動載入類別檔案 |
class Person {
private $name, $age;
public function __construct($name, $age) {
$this->name = $name; $this->age = $age;
}
public function __toString() {
return "Person: {$this->name}, {$this->age} 歲";
}
}
$p = new Person("小明", 20);
echo $p; // 輸出: Person: 小明, 20 歲
class Person {
public $name;
public $tags = [];
public function __clone() {
$this->name = "副本_" . $this->name;
$this->tags = []; // 重置標籤,避免共用陣列引用
}
}
$p1 = new Person("原始");
$p1->tags[] = "tag1";
$p2 = clone $p1;
echo $p2->name; // 副本_原始
print_r($p2->tags); // Array() - 獨立陣列
class APIClient {
private $baseUrl;
public function __call($method, $args) {
$endpoint = "/api/" . strtolower($method);
return $this->request($endpoint, $args[0] ?? []);
}
private function request($endpoint, $data) { /* HTTP 請求邏輯 */ }
}
$client = new APIClient();
$client->getUser(['id' => 1]); // 實際呼叫 request('/api/getuser', ...)
$client->createOrder(['item' => 'A']); // 實際呼叫 request('/api/createorder', ...)
class UserSession {
public $userId;
public $permissions = [];
private $dbConnection; // PDO 實例,不可序列化
public function __sleep() {
return ['userId', 'permissions']; // 僅序列化這兩個屬性
}
public function __wakeup() {
$this->dbConnection = new PDO(...); // 反序列化後重建連線
}
}
| 常數 | 說明 | 範例輸出 |
|---|---|---|
__LINE__ | 當前行號 | 25 |
__FILE__ | 完整檔案路徑(含檔名) | /var/www/html/index.php |
__DIR__ | 當前檔案目錄路徑 | /var/www/html |
__FUNCTION__ | 函數名稱(區分大小寫,PHP 5+) | myFunction |
__CLASS__ | 類別名稱(含命名空間,區分大小寫) | App\Models\User |
__METHOD__ | 類別方法名稱 | App\Models\User::getName |
__NAMESPACE__ | 當前命名空間 | App\Models |
__autoload() 已棄用 (PHP 7.2) / 移除 (PHP 8.0),僅能定義一個載入函數。
spl_autoload_register() 支援多載入器堆疊,符合 PSR-4 規範,為現代標準做法。
// 現代自動載入寫法
spl_autoload_register(function ($class) {
$file = __DIR__ . '/src/' . str_replace('\\', '/', $class) . '.php';
if (file_exists($file)) require $file;
});
__toString() 必須回傳字串,否則拋出 E_RECOVERABLE_ERROR__sleep() 回傳陣列必須為屬性名字串,否則該屬性不會被序列化__call() 僅攔截不可存取的方法(不存在或權限不足)__callStatic/__set_state)