序列化將物件 (含屬性與方法) 轉換為連續位元組字串,可儲存於檔案、資料庫或網路傳輸。反序列化則還原為記憶體中完整的物件。PHP 透過 serialize() 與 unserialize() 實作,並提供 __sleep()、__wakeup() 兩個魔術方法精細控制過程。
| 魔術方法 | 觸發時機 | 職責 | 回傳值 |
|---|---|---|---|
__sleep() | serialize($obj) 呼叫前 | 決定哪些屬性需序列化、關閉資源、提交交易等清理工作 | 必須回傳字串陣列,列出要序列化的屬性名稱;未列入者將被捨棄 |
__wakeup() | unserialize($str) 完成後 | 重建資源連線、初始化臨時屬性、解密資料等還原工作 | 無回傳值 |
<?php
class User
{
public $name;
public $id; // 臨時屬性,不需持久化
public function __construct()
{
$this->id = uniqid(); // 建立唯一暫時 ID
}
// 序列化前:明確宣告只儲存 name
public function __sleep()
{
return ["name"]; // id 將不被序列化
}
// 反序列化後:重新產生新的唯一 ID
public function __wakeup()
{
$this->id = uniqid();
}
}
// 建立物件
$u = new User();
$u->name = "Leon";
// 序列化 (id 被捨棄)
$s = serialize($u);
echo "序列化字串: $s\n";
// 輸出: O:4:"User":1:{s:4:"name";s:4:"Leon";}
// 反序列化 (id 重新產生)
$u2 = unserialize($s);
// 驗證
print_r($u);
print_r($u2);
/*
輸出差異:
User Object ( [name] => Leon [id] => 5f3a1b2c... ) // 原物件
User Object ( [name] => Leon [id] => 5f3a1d9e... ) // 新物件,id 不同
*/
?>
class Database
{
private $pdo;
private $dsn, $user, $pass;
public function __construct($dsn, $user, $pass)
{
$this->dsn = $dsn; $this->user = $user; $this->pass = $pass;
$this->connect();
}
private function connect()
{
$this->pdo = new PDO($this->dsn, $this->user, $this->pass);
}
public function __sleep()
{
// PDO 物件無法序列化,只儲存連線參數
return ["dsn", "user", "pass"];
}
public function __wakeup()
{
// 反序列化後自動重連
$this->connect();
}
}
class Credentials
{
public $username;
private $encryptedPassword;
public function setPassword($plain)
{
$this->encryptedPassword = openssl_encrypt($plain, 'AES-256-CBC', ENCRYPTION_KEY);
}
public function __sleep()
{
return ["username", "encryptedPassword"]; // 明文密碼永不序列化
}
public function __wakeup()
{
// 解密邏輯可在這裡或 getter 中實作
}
}
spl_autoload_register),否則會產生 __PHP_Incomplete_Class。private/protected 屬性同樣會被序列化 (名稱會經過 name mangling),__sleep 回傳陣列時使用原始屬性名即可。__sleep 時,需自行包含父類別屬性,或呼叫 parent::__sleep() 合併陣列。unserialize(),可能導致物件注入攻擊 (POP Chain)。PHP 7+ 提供 allowed_classes 選項限制可還原類別。JsonSerializable 介面,json_encode() 更安全、跨語言、人類可讀。__sleep 與 __wakeup 賦予 PHP 物件序列化精細控制力,是處理資源管理、敏感資料保護、臨時狀態排除的關鍵工具。但需謹記安全風險,現代架構建議優先考慮 JSON 或專用序列化庫,僅在必要時使用原生序列化。