序列化(串行化):将变量转换为可保存或传输的字符串的过程;
反序列化(反串行化):在适当的时候把这个字符串再转化成原来的变量使用。
序列化和反序列化是编程中用于处理数据对象转换过程的关键技术,它们具有以下重要作用和解决的核心问题:
1.数据持久化:
作用:将内存中的对象状态转换为易于存储(如磁盘文件、数据库记录)的格式,以便在需要时恢复对象状态。
解决的问题:应用程序关闭或重启时,内存中的对象状态会丢失。通过序列化,可以将对象状态持久化到非易失性存储介质中,确保在程序重启后仍能恢复到之前的状态。这对于用户会话管理(如登录状态、购物车内容)、游戏存档、配置数据等应用场景至关重要。
2.网络传输:
作用:将对象序列化为字节流,便于在网络间高效、安全地传输。
解决的问题:网络通信只能传输二进制数据。序列化将复杂的对象结构和数据类型转换为统一的字节流格式,便于在网络中发送和接收。接收端通过反序列化将字节流还原为与发送端一致的对象结构,实现了跨进程、跨机器甚至跨网络环境的数据交换,这对于分布式系统、远程调用(如RPC)、Web服务(如REST API)等场景必不可少。
3.进程间通信(IPC):
作用:在多个进程或线程之间传递对象状态。
解决的问题:不同进程有自己的独立内存空间,无法直接访问对方的内存对象。通过序列化,可以将对象转化为可以在进程间共享的数据格式(如管道、消息队列、共享内存等),使得不同进程间能够传递复杂数据结构。反序列化则在接收端重建对象,实现跨进程的数据同步和协作。
4.缓存:
作用:将计算结果或复杂数据结构存储在高速缓存中,以提高后续访问速度。
解决的问题:某些计算密集型或资源消耗大的操作产生的结果,如果频繁请求,直接重新计算会浪费时间和系统资源。通过序列化将结果对象存储在缓存(如Redis、Memcached)中,后续请求可以直接反序列化获取,显著提升应用性能。
5.数据备份与恢复:
作用:将关键业务数据或系统状态以序列化形式备份,用于灾难恢复或数据迁移。
解决的问题:系统故障、硬件损坏或数据丢失可能导致业务中断。定期将重要对象序列化并备份至安全位置,能够在发生问题时快速恢复数据和系统状态,保证业务连续性。
6.兼容性与互操作性:
作用:不同编程语言或系统之间通过标准的序列化格式(如JSON、XML、Protocol Buffers等)交换数据。
解决的问题:不同技术栈之间往往存在语言差异和数据模型差异。序列化提供了一种通用的数据交换格式,使得不同系统、平台或语言编写的组件能够理解和处理彼此的数据,实现跨语言、跨平台的互操作。
总结来说,序列化和反序列化主要用于解决以下几个核心问题:
数据持久化:跨越程序运行周期,保持对象状态。
网络通信:在不同系统间高效、安全地传输对象数据。
进程间通信:在不同进程间共享对象状态。
缓存机制:快速访问先前计算结果或复杂数据。
数据备份与恢复:确保业务连续性和数据安全性。
兼容性与互操作性:实现跨语言、跨平台的数据交换。
示例:
<?php
$data = array('pig', 'tiger', 'elephant');
// 序列化数据
$serialized = serialize($data);
echo $serialized;
echo "<br>";
// 反序列化数据
$unserialized = unserialize($serialized);
print_r($unserialized);
?>
第一段输出中每一个字符分别代表:
a: 表示这是一个数组(array)。
3: 表示这是一个包含3个元素的数组
i: 代表整数(integer),通常用于表示数组的索引值。
s: 代表字符串(string),在这里用于表示数组元素的取值。
具体解释如下:
i:0:代表数组中的第一个元素,其索引为0。
s:3:"pig"; 代表第一个元素的取值为"pig",即猪。
i:1:代表数组中的第二个元素,其索引为1。
s:5:"tiger"; 代表第二个元素的取值为"tiger",即老虎。
i:2:代表数组中的第三个元素,其索引为2。
s:8:"elephant"; 代表第三个元素的取值为"elephant",即大象。
综上所述,这个输入以一种结构化的方式表示了一个包含三个元素的数组,其中每个元素都有一个索引和对应的取值。
第二段输出中每一个字符分别代表:
Array:表示这是一个数组。
[0] => pig:表示数组中的第一个元素的索引为0,对应的取值为"pig",即猪。
[1] => tiger:表示数组中的第二个元素的索引为1,对应的取值为"tiger",即老虎。
[2] => elephant:表示数组中的第三个元素的索引为2,对应的取值为"elephant",即大象。
这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。常见的php系列化和反系列化方式主要有:serialize,unserialize;json_encode,json_decode。
在PHP中对不同类型的数据用不同的字母来标识:
a - array
b - boolean
d - double
i - integer
o - common object
r - reference
s - string
C - custom object
O - class
N - null
R - pointer reference
U - unicode string
N 表示的是 NULL,而 b、d、i、s 表示的是四种标量类型,目前其它语言所实现的 PHP 序列化程序基本上都实现了对这些类型的序列化和反序列化,不过有一些实现中对 s (字符串)的实现存在问题。
a、O 属于最常用的复合类型,大部分其他语言的实现都很好的实现了对 a 的序列化和反序列化,但对 O 只实现了 PHP4 中对象序列化格式,而没有提供对 PHP 5 中扩展的对象序列化格式的支持。
r、R 分别表示对象引用和指针引用,这两个也比较有用,在序列化比较复杂的数组和对象时就会产生带有这两个标示的数据。
C 是 PHP5 中引入的,它表示自定义的对象序列化方式。
U 是 PHP6 中才引入的,它表示 Unicode 编码的字符串。因为 PHP6 中提供了 Unicode 方式保存字符串的能力,因此它提供了这种序列化字符串的格式,不过这个类型 PHP5、PHP4 都不支持,而这两个版本目前是主流,因此在其它语言实现该类型时,不推荐用它来进行序列化,不过可以实现它的反序列化过程。
o标示在 PHP3 中被引入用来序列化对象,到了 PHP4 以后就被 O 取代了。在 PHP3 的源代码中可以看到对 o 的序列化和反序列化与数组 a 基本上是一样的。但是在 PHP4、PHP5 和 PHP6 的源代码中序列化部分里都找不到它。
我们知道属性访问权限有三个:private、protected、public,测试这三个属性的情况:
(1)public,该属性序列化后的结果正常,在预期之内;
(2)private,私有权限,也就是说该属性只能由类使用,为了区别,在序列化后,private属性会在自己的名字前面加上自己所属的类名,也即变成了demotest2,但是其长度为啥是11呢?写到文件使用HEXDUMP查看便知。
根据结果表明:私有属性在序列后类名前后均有%00,也即%00类名%00属性名
(3)protected,该属性和private有些类似,但是长度怎么计算呢?看上图便知!protected在序列化时序列化后的结果是%00*%00属性名
<?php
class demo
{
public $test = 'hacker';
private $test2 = 'pentester';
protected $test3 = 'redhat';
}
$object = new demo();
$uns = serialize($object);
echo $uns;
?>
总的来说就是:
public:长度正常不变,为原本名称
private:在原本名称的基础上,前面加一个类名,在类名的前后各加一个空格
protected:在原本名称的基础上,前面加一个*号,在*号前后各加一个空格
下方测试结果和上方测试结果一样,说明定义的方法不影响序列化的结果,总之:序列化只序列化属性,不序列化方法
<?php
class demo
{
public $test = 'hacker';
private $test2 = 'pentester';
protected $test3 = 'redhat';
public function test4($test)
{
$this->test4 = $test;
}
public function test5($test)
{
return $this->test;
}
}
$object = new demo();
$uns = serialize($object);
echo $uns;
?>
注意:
在反序列化的过程中必须保证当前作用域下类是存在的,否则无法完成反序列化操作。
反序列化之后的对象在文件执行结束后就会被销毁
小结:
PHP 中的 serialize() 函数用于将复杂的数据结构(如对象、数组、数值、字符串等)转换成一个可存储或传输的字符串形式。当序列化包含类实例的对象时,serialize() 对类变量的处理方式会根据这些变量的访问修饰符(public、protected、private)有所不同。