18. 串行化/序列化

有时候需要把一个对象在网络上传输,为了方便传输,可以把整个对象转化为二进制串,等到达另一端时,再还原为原来的对象,这个过程称之为串行化(也叫序列化)。

就像我们现在想把一辆汽车通过轮船运到美国去,因为汽车的体积比较大,我们可以把汽车拆开成小的部件,然后我们把这些部件通过轮般运到美国去,到了美国再把这些部件组装回汽车。

有两种情况我们必须把对象串行化,第一种情况 就是把一个对象在网络中传输的时候要将对象串行化,第二种情况 就是把对象写入文件或是数据库的时候用到串行化。

串行化有两个过程,一个是串行化 ,就是把对象转化为二进制的字符串,我们使用 serialize() 函数来串行化一个对象,另一个是 反串行化 ,就是把对象转化的二进制字符串再转化为对象, 我们使用 unserialize() 函数来反串行化一个对象。

PHP中serialize()函数的参数为对象名,返回值为一个字符串,Serialize() 返回的字符串含义模糊,一般我们不会解析这个串来得到对象的信息,我们只要把返回来的这个字符串传到网络另一端或是保存到文件中即可。

PHP中 unserialize() 函数来反串行化对象,这个函数的参数即为 serialize() 函数的返回值,输出当然是重新组织好的对象。

<?php
class Person {
    // 下面是人的成员属性
    private $name;  // 人的名子
    private $sex;   // 人的性别
    private $age;   // 人的年龄
    // 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
    function __construct($name = "", $sex = "", $age = "") {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
    // 这个人可以说话的方法, 说出自己的属性
    function say() {
        echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . "<br>";
    }
}
$p1 = new Person("张三", "男", 20);
$p1_string = serialize($p1);    // 把一个对象串行化,返一个字符串
echo $p1_string . "<br>";     // 串行化的字符串我们通常不去解析
$p2 = unserialize($p1_string);  // 把一个串行化的字符串反串行化形成对象$p2
$p2->say();

上例输出结果:

O:6:"Person":3:{s:4:"name";s:4:"张三";s:3:"sex";s:2:"男";s:3:"age";i:20;}
我的名子叫:张三 性别:男 我的年龄是:20

在PHP5中有两个魔术方法 __sleep() 方法和 __wakeup() 方法,在对象串行化的时候,会调用一个 __sleep() 方法来完成一些睡前的事情;而在重新醒来,即由二进制串重新组成一个对象的时候,则会自动调用PHP的另一个函数 __wakeup(),做一些对象醒来就要做的动作。

__sleep() 函数不接受任何参数, 但返回一个数组,其中包含需要串行化的属性。末被包含的属性将在串行化时被忽略,如果没有 __sleep() 方法,PHP将保存所有属性。

<?php
class Person {
    // 下面是人的成员属性
    var $name;  // 人的名子
    var $sex;   // 人的性别
    var $age;   // 人的年龄
    // 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
    function __construct($name = "", $sex = "", $age = "") {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
    // 这个人可以说话的方法, 说出自己的属性
    function say() {
        echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . "<br>";
    }
    // 指定串行化时把返回的数组中$name和$age值串行化,忽略没在数组中的属性$sex
    function __sleep() {
        $arr = array("name", "age"); // 此时,属性$sex将被删除!!!
        return($arr);
    }
    // 重新生成对象时,并重新赋值$age为40
    function __wakeup() {
        $this->age = 40;
    }
}
$p1 = new Person("张三", "男", 20);
// 把一个对象串行化,返一个字符串,调用了__sleep()方法,忽略没在数组中的属性$sex
$p1_string = serialize($p1);
echo $p1_string . "<br>"; // 串行化的字符串我们通常不去解析
$p2 = unserialize($p1_string); // 反串行化形成对象$p2重新赋值$age为40
$p2->say();

上例输出值为:

O:6:"Person":2:{s:4:"name";s:4:"张三";s:3:"age";i:20;}
我的名子叫:张三 性别: 我的年龄是:40