魔術方法核心清單
| 配對/單獨 | 方法 | 觸發情境 |
| 配對 | __construct / __destruct | 建構/銷毀物件 |
| 配對 | __get / __set | 讀寫不可存取屬性 |
| 配對 | __isset / __unset | isset/unset 不可存取屬性 |
| 配對 | __call / __callStatic | 呼叫不可存取方法/靜態方法 |
| 配對 | __sleep / __wakeup | 序列化/反序列化 |
| 單獨 | __clone | clone 複製物件 |
| 單獨 | __toString | 物件轉字串 |
| 單獨 | __invoke | 物件當函數呼叫 |
| 單獨 | __set_state | var_export 匯出類別 |
| 單獨 | __debugInfo | var_dump 除錯輸出 (PHP 5.6+) |
完整實作類別
<?php
class Magic {
public $var = 'test';
public function __construct() {
echo '__construct called' . PHP_EOL;
}
public function __destruct() {
echo '__destruct called' . PHP_EOL;
}
public function __set($name, $value) {
echo $name . '-' . $value . '__set called' . PHP_EOL;
}
public function __get($name) {
echo $name . '__get called' . PHP_EOL;
}
public function __call($name, $args) {
echo $name . '-' . implode(',', $args) . '__call called' . PHP_EOL;
}
public static function __callStatic($name, $args) {
echo $name . '-' . implode(',', $args) . '__callStatic called' . PHP_EOL;
}
public function __isset($name) {
echo $name . '__isset called' . PHP_EOL;
return true;
}
public function __unset($name) {
echo $name . '__unset called' . PHP_EOL;
}
public function __sleep() {
echo '__sleep called' . PHP_EOL;
return ['var1111111111']; // 故意回傳不存在屬性示範
}
public function __wakeup() {
echo '__wakeup called' . PHP_EOL;
$this->var = 'test after wakeup';
}
public function __toString() {
return '__toString called' . PHP_EOL;
}
public function __clone() {
echo '__clone called' . PHP_EOL;
}
public function __invoke() {
echo '__invoke called' . PHP_EOL;
}
public static function __set_state($arr) {
return '__set_state called' . PHP_EOL;
}
public function __debugInfo() {
echo '__debugInfo called' . PHP_EOL;
return ['var' => 'test from __debugInfo'];
}
}
// 完整測試流程
$m = new Magic(); // __construct
$m->not_exist_property = 'test'; // __set
echo $m->not_exist_property; // __get
$m->abc(1, 2, 3); // __call
Magic::staticMethod(1, 2, 3); // __callStatic
echo isset($m->not_exist_property); // __isset (回傳 bool)
unset($m->not_exist_property); // __unset
$tmp = serialize($m); // __sleep
unserialize($tmp); // __wakeup
$m1 = clone $m; // __clone
$m(); // __invoke
eval('$m2 = ' . var_export($m, true) . ';'); // __set_state
var_dump($m2);
var_dump($m); // __debugInfo
// 程式結束觸發 __destruct (多個物件依序)
執行結果輸出
__construct called
not_exist_property-test__set called
not_exist_property__get called
abc-1,2,3__call called
not_exist_property__isset called
1
not_exist_property__unset called
__sleep called
O:5:"Magic":1:{s:13:"var1111111111";N;}
__wakeup called
__destruct called
__clone called
__invoke called
string(20) "__set_state called "
class Magic#1 (1) {
public $var => string(4) "test"
}
__destruct called
__destruct called
關鍵觀察重點
__sleep 回傳的屬性名若不存在,序列化結果為 N; (null)
__wakeup 可修改物件狀態 (範例中重設 $var)
__clone 發生於 clone 關鍵字操作後,預設為淺複製
__invoke 讓物件具備可呼叫性,配合 is_callable() 判斷
__set_state 為 靜態方法,接收陣列參數回傳物件實例
__debugInfo 讓 var_dump 只顯示指定屬性,保護敏感資料
- 多物件銷毀順序:後建立先銷毀 (堆疊式)
實務應用場景
- ORM 模型:
__get/__set 實現屬性映射、__sleep 排除 PDO 連線
- 動態代理:
__call 轉發至遠端服務
- 單例模式:
__clone 拋出異常防複製
- DTO 序列化:
__sleep/__wakeup 控制快取內容
- 除錯安全:
__debugInfo 隱藏密碼、Token
相關專題
- 《PHP 基本語法入門教程》
- 《PHP 錯誤與異常處理方法總結》
- 《PHP 常用函數與技巧總結》