概念

数据(变量)序列化(持久化)

将一个变量的数据“转换为”字符串,但并不是类型转换,目的是将该字符串存储在本地,相反的行为称为反序列化
序列化和反序列化目的是是的程序间传输对象会更加方便

相关函数

serialize()
产生一个可存储的值的表示

unserialize()
从已存储的表示中创建 php 的值

php 基础

关于 php 的类与对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class test_class{
//变量
public $user = 'yichen';
//打印当前class的变量值
public function print_user()
{
echo $this->user;
}
}
//创建对象
$obj=new test_class();
//调用打印功能
$obj->print_user();
?>
image.png
image.png

序列化

接下来看一下序列化相关的内容,首先看一下序列化之后的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class user
{
public $name = 'yichen';
public $age = 20;
public function print_data()
{
echo $this->name.' is '.$this->age.' years old<br>';
}
}
$user1 = new user();
$user1->age=21;
$user1->name='y1chen';
$user1->print_data();
echo serialize($user1);
?>

结果:y1chen is 21 years old
O:4:”user”:2:{s:4:”name”;s:6:”y1chen”;s:3:”age”;i:21;}

解释:O 表示对象,4 表示对象名的长度,后面跟的是对象名
2 表示里面有两个变量
s 表示变量是字符串,4 意思是变量名有 4 的长度,后面跟着的值的部分表示,一样
i 意思是变量赋的值是整形,值为 21

反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class user
{
public $name = 'yichen';
public $age = 20;
public function print_data()
{
echo $this->name.' is '.$this->age.' years old<br>';
}
}
$user1 = new user();
$user1->age=21;
$user1->name='y1chen';
$user1->print_data();
echo serialize($user1);
//O:4:"user":2:{s:4:"name";s:6:"y1chen";s:3:"age";i:21;}
$user2 = unserialize('O:4:"user":2:{s:4:"name";s:6:"y1chen";s:3:"age";i:21;}');
echo "<br>";
$user2->print_data($user2);
?>
image.png
image.png

魔术方法

{Q9J${2WQL@H5`[3X75N6KI.png
{Q9J${2WQL@H5`[3X75N6KI.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
highlight_file(__FILE__);
header("Content_type:text/html;charset=utf-8");
class magic_test
{
public $data1="Tony";
public $data2="Leo";
public function print_dat()
{
echo $this->data1 .$this->data2 . "<br>";
}
public function __construct()
{
echo "__construct<br>";
}
public function __destruct()
{
echo "__destruct<br>";
}
public function __wakeup()
{
echo "__wakeup<br>";
}
//__sleep() 该函数必须返回一个需要进行序列化保存的成员属性数组,并且只序列化该函数返回的这些成员属性
public function __sleep()
{
echo "__sleep<br>";
return array("data1","data2");
#return array("data");
}
}
//创建对象,调用__construct
echo "准备创建对象<br>";
$obj = new magic_test();
echo "创建对象完成<br>";

//序列化对象,调用__sleep
echo "准备序列化对象<br>";
$serialized = serialize($obj);
echo "序列化对象完成<br>";

//输出序列化之后的字符串
echo "打印序列化之后的对象";
echo "serialized: ".$serialized."<br>";
echo "打印完成<br>";

//重建对象,调用__wakeup
echo "准备反序列化对象<br>";
$obj2=unserialize($serialized);
echo "反序列化完成<br>";

//调用方法
echo "准备调用方法<br>";
$obj2->print_dat();
echo "调用结束<br>";

//反序列化后会额外在调用__destruct
//脚本结束 调用__destruct
?>

注意点

直接变量名反序列化出来的是 public 变量
\x00+类名+\x00+变量名 反序列化出来是 private 变量
\x00+*+\x00+变量名 反序列化出来是 protected 变量
浏览器会不显示,用终端
在对象长度前面可以加符号(+-)

PHP BUG

当序列化字符串中,如果表示对象属性的个数的值大于真实的属性个数时就会跳过__wakeup 的执行