序列化將變數(特別是物件)轉換為可儲存、可傳輸的字串格式;反序列化則還原為原始結構。PHP 原生 serialize()/unserialize() 支援所有型別,含物件完整狀態。
$user = new class {
public string $name = 'Alice';
public int $age = 25;
private string $secret = 'hidden';
};
// 序列化
$serialized = serialize($user);
// 'O:8:"stdClass":3:{s:4:"name";s:5:"Alice";s:3:"age";i:25;s:15:"\0stdClass\0secret";s:6:"hidden";}'
// 儲存至檔案
file_put_contents('user.dat', $serialized);
// 反序列化(需確保類別定義已載入)
$data = file_get_contents('user.dat');
$user = unserialize($data);
| 方法 | 觸發時機 | 用途 | 回傳值 |
|---|---|---|---|
__sleep() | 序列化前 | 清理資源、選擇要序列化的屬性 | string[] 屬性名稱陣列 |
__wakeup() | 反序列化後 | 重建資源連線、初始化狀態 | 無 |
__serialize() | 序列化前 (PHP 7.4+) | 自訂序列化資料結構 | array 任意資料 |
__unserialize($data) | 反序列化後 (PHP 7.4+) | 從自訂資料還原狀態 | 無 |
class User {
public $id;
public $name;
private $password; // 敏感資料不應序列化
private $dbConnection; // 資源型別無法序列化
public function __sleep() {
// 關閉資料庫連線
if ($this->dbConnection) {
$this->dbConnection->close();
}
// 僅回傳需序列化的屬性名稱
return ['id', 'name'];
}
}
class User {
// ... 屬性定義
public function __wakeup() {
// 重新建立資料庫連線
$this->dbConnection = new PDO($this->dsn, $this->user, $this->pass);
// 觸發延遲載入邏輯
$this->loadPermissions();
}
}
Serializable 介面已棄用,改用 __serialize()/__unserialize():
class DataTransferObject {
private $data = [];
private $computedCache = [];
public function __serialize(): array {
// 僅序列化核心資料,忽略快取
return ['data' => $this->data];
}
public function __unserialize(array $data): void {
$this->data = $data['data'];
$this->computedCache = []; // 重置快取
}
}
| 方法 | 觸發情境 | 用途 |
|---|---|---|
__toString() | 物件當作字串使用 | 回傳字串表示,如 echo $obj |
__invoke() | 物件當作函數呼叫 | 使物件可呼叫,閉包即實作此方法 |
__debugInfo() | var_dump() 物件 | 自訂除錯輸出內容(隱藏敏感資訊) |
class ApiResponse {
private $data;
private $token;
public function __toString() {
return json_encode($this->data);
}
public function __invoke($key) {
return $this->data[$key] ?? null;
}
public function __debugInfo() {
return ['data' => $this->data, 'token' => '[HIDDEN]'];
}
}
$resp = new ApiResponse();
$resp->data = ['user' => 'Alice'];
$resp->token = 'secret123';
echo $resp; // {"user":"Alice"}
echo $resp('user'); // Alice
var_dump($resp); // token 顯示 [HIDDEN]
unserialize() 會實例化物件並呼叫 __wakeup()/__destruct(),惡意資料可能導致 RCE。絕不反序列化不可信資料,或使用 unserialize($data, ['allowed_classes' => ['User', 'DTO']]) 限制允許類別(PHP 7.0+)。