PHP Conference Japan 2024

serialize

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

serialize生成值的可存储表示形式

描述

serialize(混合 $value): 字符串

生成值的可存储表示形式。

这对于存储或传递 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 条注释

egingell at sisna dot com
18 年前
<?
/*
序列化值的结构

字符串
s:size:value;

整数
i:value;

布尔值
b:value;(不存储“true”或“false”,存储'1'或'0')

空值
N;

数组
a:size:{key definition;value definition;(repeated per element)}

对象
O:strlen(object name):object name:object size:{s:strlen(property name):property name:property definition;(repeated per property)}

字符串值始终用双引号括起来
数组键始终是整数或字符串
"null => 'value'" 等价于 's:0:"";s:5:"value";',
"true => 'value'" 等价于 'i:1;s:5:"value";',
"false => 'value'" 等价于 'i:0;s:5:"value";',
"array(whatever the contents) => 'value'" 会导致“非法偏移量类型”警告,因为您不能使用
数组作为键;但是,如果您使用包含数组的变量作为键,它将等价于 's:5:"Array";s:5:"value";',
并且
尝试使用对象作为键将导致与使用数组相同的行为。
*/
?>
匿名
12 年前
拜托!拜托!拜托!不要序列化数据并将其放入数据库中。serialize 可以这样使用,但这忽略了关系数据库和数据库引擎固有数据类型的意义。这样做会使数据库中的数据不可移植、难以阅读,并可能使查询复杂化。如果您希望您的应用程序可移植到其他语言,例如,假设您发现您希望在应用程序的某些部分使用 Java,那么序列化将变得非常麻烦。您应该始终能够查询和修改数据库中的数据,而无需使用第三方中间工具来处理要插入的数据。

在我的职业生涯中遇到过太多次这种情况,它会导致难以维护的代码、可移植性存在问题的代码以及更难以迁移到其他 RDMS 系统、新模式等的数据。它还具有使根据您已序列化的某个字段搜索数据库变得混乱的额外缺点。

这并不是说 `serialize()` 毫无用处。它并非如此……一个可以使用它的好地方可能是包含数据密集型操作结果的缓存文件,例如。还有很多其他地方……只是不要滥用 `serialize()`,因为下一个接手的人将会遇到维护或迁移的噩梦。
mark at bvits dot co dot uk
1 年前
到目前为止,用户注释中没有提到一种类型“E”。这是可以利用的较新的枚举类 `Enum`。

login_security|E:25:"Permission:manageClient"
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 是 Class A 的另一个对象。

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

所有引用都保持完整。
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()` 更快)。
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>";
?>
frost at easycast dot ru
11 年前
闭包无法被序列化
<?php
$func
= function () {echo 'hello!';};
$func(); // 输出 "hello!"

$result = serialize($func); // 致命错误:未捕获的异常“Exception”,消息为“不允许序列化'Closure'”
?>
To Top