PHP 中 serialize()/unserialize() 與 json_encode()/json_decode() 是兩大序列化方案。它們在數據類型支援、跨語言互操作、性能、安全性上有本質差異。本文通過實測代碼詳細對比,給出選型指南。
$obj = new stdClass();
$obj->site = 'tantengvip';
$obj->owner = 'tuntun';
$obj->age = 5;
$arr = [
'site' => 'tantengvip',
'owner' => 'tuntun',
'age' => 5,
];
var_dump(serialize($obj));
// string(87) 'O:8:"stdClass":3:{s:4:"site";s:10:"tantengvip";s:5:"owner";s:6:"tuntun";s:3:"age";i:5;}'
var_dump(unserialize(serialize($obj)));
// object(stdClass)#2 (3) { ["site"]=> string(10) "tantengvip" ["owner"]=> string(6) "tuntun" ["age"]=> int(5) }
var_dump(serialize($arr));
// string(74) 'a:3:{s:4:"site";s:10:"tantengvip";s:5:"owner";s:6:"tuntun";s:3:"age";i:5;}'
var_dump(json_encode($obj));
// string(46) '{"site":"tantengvip","owner":"tuntun","age":5}'
var_dump(json_decode(json_encode($obj)));
// object(stdClass)#2 (3) { ["site"]=> string(10) "tantengvip" ["owner"]=> string(6) "tuntun" ["age"]=> int(5) }
var_dump(json_decode(json_encode($obj), true)); // 第二參數 true → 關聯數組
// array(3) { ["site"]=> string(10) "tantengvip" ["owner"]=> string(6) "tuntun" ["age"]=> int(5) }
class Test {
private $pri = 'pri';
public $pub = 'pub';
public function __construct() {
$this->pri = 'pri_construct';
$this->pub = 'pub_construct';
}
}
$test = new Test();
// serialize:保留類名、私有屬性、構造函數初始值
var_dump(serialize($test));
// 'O:4:"Test":2:{s:9:"\0Test\0pri";s:13:"pri_construct";s:3:"pub";s:12:"pub_construct";}'
var_dump(unserialize(serialize($test)));
// object(Test)#2 (2) { ["pri":"Test":private]=> string(13) "pri_construct" ["pub"]=> string(12) "pub_construct" }
// json:丟失私有屬性、類名變為 stdClass
var_dump(json_encode($test));
// '{"pub":"pub_construct"}'
var_dump(json_decode(json_encode($test)));
// object(stdClass)#2 (1) { ["pub"]=> string(12) "pub_construct" }
| 維度 | serialize | json_encode |
|---|---|---|
| 數據格式 | PHP 專有二進制兼容文本 | 標準 JSON (RFC 8259) |
| 跨語言 | 不支援 | 完美支援 |
| 類型保真度 | 高(類名、私有/保護屬性、資源類型) | 低(僅公有屬性、stdClass、基本類型) |
| 編碼要求 | 任意編碼 | 必須 UTF-8 |
| 可讀性 | 差 | 高 |
| 體積 | 較大(含類型元信息) | 較小 |
| 性能 | 稍快(C 級實現) | 稍慢(UTF-8 驗證、轉義) |
| 安全性 | 反序列化漏洞風險(__wakeup/__destruct 鏈) | 安全(無代碼執行) |
| 魔術方法 | 支援 __sleep/__wakeup/__serialize/__unserialize | 支援 JsonSerializable 接口 |
| 資源類型 | 可序列化(句柄轉標識符) | 不支援(返回 null) |
JsonSerializable 手動控制輸出// 惡意構造的序列化字符串可觸發 __wakeup/__destruct 鏈 // 導致任意代碼執行、文件讀寫、SSRF 等 // 禁止對不可信數據調用 unserialize() // 必須使用: // 1. JSON 替代 // 2. 如果必須用,PHP 7.0+ 提供 allowed_classes 參數 $data = unserialize($untrusted, ['allowed_classes' => ['MySafeClass']]); // 3. 簽名驗證:存儲時 HMAC-SHA256 簽名,讀取時驗證後再反序列化
json_encode/json_decode 作為默認序列化方案JsonSerializable 接口精確控制輸出Cache::set($key, $value) 內部自動選擇(純數據用 json,對象用 serialize)unserialize → json_encode → 重寫理解兩者本質差異,根據場景選擇,既能享受 JSON 的通用性,又能在需要時利用 serialize 的類型保真度。