PHP Conference Japan 2024

serialize

(PHP 4, PHP 5, PHP 7, PHP 8)

serialize產生值的可儲存表示法

描述

serialize(mixed $value): string

產生值的可儲存表示法。

這對於儲存或傳遞 PHP 值,而不會遺失其型別和結構非常有用。

要將序列化的字串再次轉換為 PHP 值,請使用 unserialize()

參數

value

要序列化的值。serialize() 處理所有型別,除了 資源型別和一些 物件 (請參閱下面的注意事項)。您甚至可以 serialize() 包含對自身參照的陣列。您正在序列化的陣列/物件內的循環參照也會被儲存。任何其他參照都會遺失。

在序列化物件時,PHP 會嘗試在序列化之前呼叫成員函式 __serialize()__sleep()。這是為了允許物件在序列化之前執行任何最後的清理等動作。同樣地,當使用 unserialize() 還原物件時,會呼叫 __unserialize()__wakeup() 成員函式。

注意:

物件的私有成員在其成員名稱前加上類別名稱;受保護的成員在其成員名稱前加上 '*'。這些前置值在兩側都有空位元組。

回傳值

回傳一個包含 value 的位元組串表示法的字串,該字串可以儲存在任何地方。

請注意,這是一個二進制字串,可能包含空位元組,需要像這樣儲存和處理。例如,serialize() 輸出通常應儲存在資料庫的 BLOB 欄位中,而不是 CHAR 或 TEXT 欄位中。

範例

範例 #1 serialize() 範例

<?php
// $session_data 包含一個多維陣列,其中包含目前使用者的工作階段
// 資訊。我們使用 serialize() 在請求結束時將其儲存到資料庫中。

$conn = odbc_connect("webdb", "php", "chicken");
$stmt = odbc_prepare($conn,
"UPDATE sessions SET data = ? WHERE id = ?");
$sqldata = array (serialize($session_data), $_SERVER['PHP_AUTH_USER']);
if (!
odbc_execute($stmt, $sqldata)) {
$stmt = odbc_prepare($conn,
"INSERT INTO sessions (id, data) VALUES(?, ?)");
if (!
odbc_execute($stmt, array_reverse($sqldata))) {
/* 發生了一些問題.. */
}
}
?>

注意

注意:

請注意,許多內建的 PHP 物件無法序列化。然而,那些具備此能力的物件,要么實作了 Serializable 介面,要么實作了魔法方法 __serialize()/__unserialize()__sleep()/__wakeup()。如果內部類別不符合這些要求,則無法可靠地序列化。

上述規則有一些歷史例外,某些內部物件可以在不實作介面或公開方法的情況下序列化。

警告

serialize() 序列化物件時,為了最大的相容性,命名空間類別的類別名稱中不會包含前導反斜線。

參閱

新增註解

使用者貢獻的註解 7 個註解

363
egingell at sisna dot com
18 年前
<?
/*
serialize()'ed 值的剖析

字串
s:大小:值;

整數
i:值;

布林值
b:值; (不儲存 "true" 或 "false",儲存 '1' 或 '0')

Null
N;

陣列
a:大小:{索引鍵定義;值定義;(每個元素重複)}

物件
O:strlen(物件名稱):物件名稱:物件大小:{s:strlen(屬性名稱):屬性名稱:屬性定義;(每個屬性重複)}

字串值始終使用雙引號
陣列索引鍵始終是整數或字串
"null => 'value'" 等於 's:0:"";s:5:"value";',
"true => 'value'" 等於 'i:1;s:5:"value";',
"false => 'value'" 等於 'i:0;s:5:"value";',
"array(無論內容為何) => 'value'" 等於「非法偏移類型」警告,因為您無法使用
陣列作為索引鍵;但是,如果您使用包含陣列的變數作為索引鍵,它將等於 's:5:"Array";s:5:"value";',
並且
嘗試使用物件作為索引鍵將導致與使用陣列相同的行為。
*/
?>
281
匿名
12 年前
拜託!拜託!拜託!請「不要」將資料序列化後放入資料庫。序列化可以用於這種方式,但這就失去了關聯式資料庫的意義,以及資料庫引擎中固有的資料型別。這樣做會使您資料庫中的資料無法移植、難以閱讀,並且會使查詢複雜化。如果您希望您的應用程式可以移植到其他語言,例如您發現您想在應用程式的某些部分使用 Java(因為在這些部分使用 Java 是合理的),那麼序列化將會變得非常麻煩。您應該始終能夠在不使用第三方中介工具來操作要插入的資料的情況下,查詢和修改資料庫中的資料。

我在我的職業生涯中遇到過太多次這種情況了,它會導致程式碼難以維護、程式碼出現移植性問題,以及資料更難遷移到其他 RDMS 系統、新的 schema 等。它還有一個額外的缺點,就是當您想基於您序列化的其中一個欄位來搜尋資料庫時,會變得非常混亂。

這並不是說 `serialize()` 沒有用處。它並非如此… 一個適合使用它的地方可能是快取檔案,其中包含資料密集型操作的結果。還有很多其他的用途… 只是不要濫用序列化,因為下一個接手的人將會面臨維護或遷移的噩夢。
3
mark at bvits dot co dot uk
1 年前
到目前為止,在使用者筆記中沒有提到一種型別 'E'。這是較新的 Enum 類別,可以使用。

login_security|E:25:"Permission:manageClient"
21
MC_Gurk at gmx dot net
18 年前
如果您要序列化一個包含對其他物件的引用的物件,而您稍後要序列化這些物件,則當物件被反序列化時,這些引用將會遺失。
只有當您的所有物件同時被序列化時,才能保留這些引用。
這表示

$a = new ClassA();
$b = new ClassB($a); //$b 包含對 $a 的引用;

$s1=serialize($a);
$s2=serialize($b);

$a=unserialize($s1);
$b=unserialize($s2);

現在 b 引用一個 ClassA 的物件,但它不是 $a。$a 是另一個 ClassA 的物件。

使用這個
$buf[0]=$a;
$buf[1]=$b;
$s=serialize($buf);
$buf=unserialize($s);
$a=$buf[0];
$b=$buf[1];

所有的引用都完好無損。
25
nh at ngin dot de
11 年前
序列化浮點數會導致奇怪的精度偏移錯誤

<?php

echo round(96.670000000000002, 2);
// 96.67

echo serialize(round(96.670000000000002, 2));
// d:96.670000000000002;

echo serialize(96.67);
// d:96.670000000000002;

?>

這不僅是錯誤的,而且還會為序列化的資料增加許多不必要的體積。最好改用 json_encode()(顯然它比 serialize() 快)。
11
Andrew B
12 年前
當您序列化陣列時,內部指標將不會被保留。顯然,這是預期的行為,但對我來說是一個有點意外的情況。複製並貼上下面的範例。

<?php
// 一旦變數被指定,內部指標將會是 2。
$array = array();
$array[] = 1;
$array[] = 2;
$array[] = 3;

// 取消設置變數。內部指標仍將在 2。
unset($array[0]);
unset(
$array[1]);
unset(
$array[2]);

// 序列化
$serializeArray = serialize($array);

// 反序列化
$array = unserialize($serializeArray);

// 向陣列新增一個新的元素
// 如果內部指標被保留,則新的陣列鍵應該是 3。
// 相反,內部指標已被重置,並且新的陣列鍵是 0。
$array[] = 4;

// 預期的鍵 - 3
// 實際的鍵 - 0
echo "<pre>" , print_r($array, 1) , "</pre>";
?>
12
frost at easycast dot ru
11 年前
閉包不能被序列化
<?php
$func
= function () {echo 'hello!';};
$func(); // 印出 "hello!"

$result = serialize($func); // 致命錯誤:捕捉到的例外 'Exception',訊息為 'Serialization of 'Closure' is not allowed'
?>
To Top