PHP序列化和反序列化详解
最近,在看PHP官方文档时,发现官方文档中关于序列化的内容并不是非常详细,下面我就详细介绍一下PHP序列化和反序列化
serialize()和unserialize()函数
用法
serialize()
函数可以把数字、字符串、数组以及对象进行序列化,并返回序列化后的字符串。unserialize()
函数可以把序列化的字符串你,还原原来的结构
实例
整型
序列化和反序列化整型变量
<?php
$data = 56;
$serialized_data = serialize($data);
echo "序列化:".$serialized_data . PHP_EOL;
$unserialized_data = unserialize($serialized_data);
echo "反序列化:".$unserialized_data . PHP_EOL;
?>
输出:
序列化:i:56;
反序列化:56
浮点型
序列化和反序列化浮点型变量
输入:56.012
<?php
$data = 56.012;
$serialized_data = serialize($data);
echo "序列化:".$serialized_data . PHP_EOL;
$unserialized_data = unserialize($serialized_data);
echo "反序列化:".$unserialized_data . PHP_EOL;
?>
输出:
序列化:d:56.012;
反序列化:56.012
输入:56.452
<?php
$data = 56.452;
$serialized_data = serialize($data);
echo "序列化:".$serialized_data . PHP_EOL;
$unserialized_data = unserialize($serialized_data);
echo "反序列化:".$unserialized_data . PHP_EOL;
?>
输出:
序列化:d:56.451999999999998;
反序列化:56.452
字符串
序列化和反序列化字符串变量
<?php
$data = "acdef";
$serialized_data = serialize($data);
echo "序列化:".$serialized_data . PHP_EOL;
$unserialized_data = unserialize($serialized_data);
echo "反序列化:".$unserialized_data . PHP_EOL;
?>
输出:
序列化:s:5:"acdef";
反序列化:acdef
数组
序列化和反序列化数组
<?php
$data = array("Thor","Iornman","Cap");
$serialized_data = serialize($data);
echo "序列化:".$serialized_data . PHP_EOL;
$unserialized_data = unserialize($serialized_data);
echo "反序列化:". PHP_EOL;
var_dump($unserialized_data);
?>
输出:
反序列化:
array (size=3)
0 => string 'Thor' (length=4)
1 => string 'Iornman' (length=7)
2 => string 'Cap' (length=3)
序列化:a:3:{i:0;s:4:"Thor";i:1;s:7:"Iornman";i:2;s:3:"Cap";}
对象
序列化和反序列化对象,serialize
只会把对象成员变量序列化。
<?php
class Book{
private $num;
private $title;
private $writer;
function __construct($num,$title,$writer){
$this->num = $num;
$this->title = $title;
$this->writer = $writer;
}
private function test(){
echo "test";
}
}
$book = new Book(001,"算法","作者");
$serialized_data = serialize($book);
echo "序列化:".$serialized_data . PHP_EOL;
$unserialized_data = unserialize($serialized_data);
echo "反序列化:". PHP_EOL;
var_dump($unserialized_data);
?>
输出:
反序列化:
object(Book)[2]
private 'num' => int 1
private 'title' => string '算法' (length=6)
private 'writer' => string '作者' (length=6)
序列化:O:4:"Book":3:{s:9:"Booknum";i:1;s:11:"Booktitle";s:6:"算法";s:12:"Bookwriter";s:6:"作者";}
另:序列化对象时,不会保存常量的值。对于父类中的变量,则会保留。
当反序列化对象之前,未定义类时会正常输入,但反序列化得到的对象是__PHP_Incomplete_Class
,并指定了未定义类的类名。
$serialized_data = 'O:4:"User":2:{s:8:"username";s:7:"Iornman";s:8:"nickname";s:6:"尼尼";}';
var_dump(unserialize($serialized_data));
输出:
object(__PHP_Incomplete_Class)[1]
public '__PHP_Incomplete_Class_Name' => string 'User' (length=4)
public 'username' => string 'Iornman' (length=7)
public 'nickname' => string '尼尼' (length=6)
其他
布尔类型和NUll序列化后的字符串格式如下:
Boolean
: b:value;(1或0)Null
: N;
sleep()和wakeup()魔术方法
有时,我们并不想将对象中的所有成员变量都进行序列化,而是有选择的进行序列化,这时就要用到__sleep()
魔术方法。
__sleep()用法
当时使用serialize()
进行序列化对象时,如果存在__sleep()
魔术方法,则会先调用此方法,然后才执行序列化。
__wakeup()用法
当时使用unserialize()
进行反序列化对象时,如果存在__wakeup()
魔术方法,则会先调用此方法,然后才执行反序列化。
实例
利用__sleep()
魔术方法过滤掉一些敏感变量,使其不进行序列化。
<?php
class User{
public $username;
public $nickname;
private $password;
public function __construct($username, $nickname, $password)
{
$this->username = $username;
$this->nickname = $nickname;
$this->password = $password;
}
// 重载序列化调用的方法
public function __sleep()
{
// 返回需要序列化的变量名,过滤掉password变量
return array('username', 'nickname');
}
public function __wakeup(){
echo "执行__wakeup";
}
}
$user = new User('Iornman', '尼尼', '123456');
$serialized_data = serialize($user);
var_dump($serialized_data);
$unserialized_data = unserialize($serialized_data);
var_dump($unserialized_data);
?>
输出:
string 'O:4:"User":2:{s:8:"username";s:7:"Iornman";s:8:"nickname";s:6:"尼尼";}' (length=72)
执行__wakeup
object(User)[2]
public 'username' => string 'Iornman' (length=7)
public 'nickname' => string '尼尼' (length=6)
private 'password' => null
序列化接口Serializable
当使用__sleep()
时,存在一个问题,__sleep()
无法将父类的成员变量序列化,我们可以使用Serializable
序列化接口来解决这个问题。
实例
让父类继承Serializable接口,并在父类中重写Serializable提供的serialize()
和unserialize()
方法。当父类继承Serializable接口时,子类中的__sleep()
和__wakeup()
将不再被调用。
<?php
class Common implements Serializable{
public $publc_val;
private $private_val = '123';
//重写Serializable接口提供的方法
public function serialize()
{
echo __METHOD__ . "\n";
return serialize($this->private_val);
}
//重写Serializable接口提供的方法
public function unserialize($serialized)
{
echo __METHOD__ . "\n";
}
}
class User extends Common{
public $username;
public $nickname;
private $password;
public function __construct($username, $nickname, $password)
{
$this->username = $username;
$this->nickname = $nickname;
$this->password = $password;
}
// 重载序列化调用的方法
public function __sleep()
{
// 返回需要序列化的变量名,过滤掉password变量
echo __METHOD__;
}
public function __wakeup(){
echo __METHOD__;
}
}
$user = new User('Iornman', '尼尼', '123456');
$serialized_data = serialize($user);
var_dump($serialized_data);
$unserialized_data = unserialize($serialized_data);
var_dump($unserialized_data);
?>
输出:
Common::serialize
object(User)[2]
public 'username' => null
public 'nickname' => null
private 'password' => null
public 'publc_val' => null
private 'private_val' (Common) => null
Common::unserialize
string 'C:4:"User":10:{s:3:"123";}' (length=26)