简介
序列化就是将一个值转换为字符串,并可将字符串存入硬盘文件、数据库等。任何时候只要将这个字符串作反序列化操作,就可还原出原来的值。
serialize()
string serialize ( mixed $value )
序列化值$value,并以字符串形式返回。serialize() 可处理除了 resource 之外的任何类型。甚至可以 serialize() 那些包含了指向其自身引用的数组。你正 serialize() 的数组/对象中的引用也将被存储。
unserialize()
mixed unserialize ( string $str )
对单一的已序列化的变量进行操作,将其转换回 PHP 的值。注意,序列化得到的字符串中是包含类型信息的,所以反序列化得到的结果不需要再次执行类型转换。
正常情况下返回的是转换之后的值,可为 integer、float、string、array 或 object类型。 如果传递的字符串不可解序列化,则返回 FALSE,并产生一个 E_NOTICE。 如果反序列化了 FALSE 的值,或者在过程中发生了错误,都会返回 FALSE。 可以通过 str 和 serialize(false) 进行比较,或者捕捉 E_NOTICE 错误来判断这种特殊情况。
$a = 78;
$b = "abc";
$c = true;
$d = null;
$e = [[1,2],[3,4]];
$sa = serialize($a);
$sb = serialize($b);
$sc = serialize($c);
$sd = serialize($d);
$se = serialize($e);
echo "$sa\n"; // i:78;
echo "$sb\n"; // s:3:"abc";
echo "$sc\n"; // b:1;
echo "$sd\n"; // N;
echo "$se\n"; // a:2:{i:0;a:2:{i:0;i:1;i:1;i:2;}i:1;a:2:{i:0;i:3;i:1;i:4;}}
$a = unserialize($sa);
$b = unserialize($sb);
$c = unserialize($sc);
$d = unserialize($sd);
$e = unserialize($se);
var_dump($a);
var_dump($b);
var_dump($c);
var_dump($d);
var_dump($e);
/*
int(78)
string(3) "abc"
bool(true)
NULL
array(2) {
[0]=>
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
[1]=>
array(2) {
[0]=>
int(3)
[1]=>
int(4)
}
}
*/
序列化对象
序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。 所以,为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。 如果要想在另外一个文件中解序列化一个对象,这个对象的类必须在解序列化之前定义。如果在解序列化对象的时候,没有找到该对象的类的定义,将会使用__PHP_Incomplete_Class_Name作为该对象的类,导致返回一个没有用的对象。
可以通过包含一个定义该类的文件或使用函数spl_autoload_register()来实现。
也可以通过配置项unserialize_callback_func来实现类的自动加载:
ini_set('unserialize_callback_func', 'mycallback'); // 设置回调函数
function mycallback($classname)
{
// 只需包含含有类定义的文件
// $classname 指出需要的是哪一个类
}
serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。
注意,__sleep() 不能返回父类的私有成员的名字。可以用 Serializable 接口来替代。
unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。 __wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
class MyClass
{
public $a = 5;
public $b = 6;
public $c = 7;
public function __sleep() {
return array("b");
}
public function __wakeup() {
$this->c = 0;
}
}
$var = new MyClass();
$var->a = 555;
$var->b = 666;
$str = serialize($var);
$var = unserialize($str);
var_dump($var);
/*
object(MyClass)#2 (3) {
["a"]=>
int(5)
["b"]=>
int(666)
["c"]=>
int(0)
}
*/
Serializable 序列化接口
一个类通过实现此接口,可自定义序列化和反序列化的过程,该接口包含如下两个方法:
abstract public string serialize ( void )
abstract public mixed unserialize ( string $serialized )
实现此接口的类将不再支持 __sleep() 和 __wakeup()。不论何时,只要有实例需要被序列化,serialize 方法都将被调用。它将不会调用 __destruct() 或有其他影响,除非程序化地调用此方法。当数据被反序列化时,类将被感知并且调用合适的 unserialize() 方法而不是调用 __construct()。如果需要执行标准的构造器,你应该在这个方法中进行处理。
下例中,类在序列化时只保存了部分父类私有成员。
class Base
{
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
protected function getA() {
return $this->a;
}
}
class MyClass extends Base implements Serializable
{
public function __construct($a, $b) {
parent::__construct($a, $b);
}
public function serialize() {
return serialize($this->getA());
}
public function unserialize($str) {
$a = unserialize($str);
parent::__construct($a, 0);
}
}
$var = new MyClass(5, 6);
var_dump($var);
$str = serialize($var);
$var = unserialize($str);
var_dump($var);
/*
object(MyClass)#1 (2) {
["a":"Base":private]=>
int(5)
["b":"Base":private]=>
int(6)
}
object(MyClass)#2 (2) {
["a":"Base":private]=>
int(5)
["b":"Base":private]=>
int(0)
}
*/