PHP序列化中serialize与unserialize函数

逄征
2023-12-01

在php中,序列化用与存储或传递php的值的过程,同时不丢失其结构和数据类型。函数包括serialize()、unserialize();魔术方法包括__sleep() wakeup(); 预定义接口Serializable;

目录

【1】serialize()与unserialize()

【2】各种变量的序列化结果

【3】序列化对象

【4】序列化对象中的__sleep()魔术方法

【5】file_put_contents保存序列化值到文件

【6】反序列化对象中的__wakeup()魔术方法

【7】序列化接口Serializable

【8】小结


【1】serialize()与unserialize()

      serialize() 返回字符串,此字符串包含了表示 value 的字节流,可以存储于任何地方。这有利于存储或传递 PHP 的值,同时不丢失其类型和结构。serialize() 可处理除了 resource 之外的任何类型。甚至可以 serialize() 那些包含了指向其自身引用的数组。你正 serialize() 的数组/对象中的引用也将被存储。

函数用法:
	serialize ( mixed $value ) : string
作用:
	用于序列化对象或数组,并返回一个字符串。
例子:
	$sites = ['Google','bing','Baidu'];
    $data  = serialize($sites);
    echo $data;//a:3:{i:0;s:6:"Google";i:1;s:4:"bing";i:2;s:5:"Baidu";}

      unserialize() 函数用于将通过 serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。

函数用法:
	unserialize ( string $str ) : mixed
作用:
	对单一的已序列化的变量进行操作,将其转换回 PHP 的值
例子:
	$str = 'a:3:{i:0;s:6:"Google";i:1;s:4:"bing";i:2;s:5:"Baidu";}';
    $data=unserialize($str);
    var_dump($data);
 /*
    array (size=3)
      0 => string 'Google' (length=6)
      1 => string 'bing' (length=4)
      2 => string 'Baidu' (length=5)
*/

【2】各种变量的序列化结果

         以下表格也是我实践看到的,可能不是很官方或者全面。

变量类型进行serialize标志
inti:9;i
strings:5:"Tacks";s
doubled:9.9000000000000004;d
boolb:1;b
arraya:4:{i:0;i:1;i:1;s:3:"two";i:2;d:2;i:3;b:1;}a
nullN;N
objectO:6:"People":0:{}O
$num  = 9;
$data = serialize($num);
echo $data,'<br/>';//i:9;

$str  = 'Tacks';
$data = serialize($str);
echo $data,'<br/>';//s:5:"Tacks";

$decimal = 9.9;
$data = serialize($decimal);
echo $data,'<br/>';//d:9.9000000000000004;
 
$bool = true;
$data = serialize($bool);
echo $data,'<br/>';//b:1;

$arr  = [1,'two',2.0,true];
$data = serialize($arr);
echo $data,'<br/>';//a:4:{i:0;i:1;i:1;s:3:"two";i:2;d:2;i:3;b:1;}

$null = null;
$data = serialize($null);
echo $data,'<br/>';//N;

class People{};
$obj  = new People;
$data = serialize($obj);
echo $data,'<br/>';//O:6:"People":0:{}


$res  = opendir('../written');//打开一个目录返回资源类型
$data = serialize($res);
echo $data,'<br/>';//i:0;  #实际上最好不去执行资源类型

function my_callback_function() {
    echo 'GGG';
}
$back = call_user_func('my_callback_function');
$data = serialize($back);
echo $data,'<br/>';//GGGN; #这个回调

【3】序列化对象

            序列化对象时,不会保存常量的值;对象的受保护类型的属性名,会有一个*号区别,对于父类中的变量,则会保留;可以看一下下面的例子。

class Animal{
    public $type = 'Animal';
}
class Bird extends Animal{
    const wings = 2;
    public    $name;
    protected $age;
    private   $weight;
    public function __construct($name,$age,$weight){
        $this->name = $name;
        $this->age = $age;
        $this->weight = $weight;
    }
}
$bigBird = new Bird('Big sparrow',9,'10KG');
echo serialize($bigBird);
/*
输出的结果整理一下格式看的清楚一些
O:4:"Bird":4:{
    s:4:"name";s:11:"Big sparrow";
    s:6:"*age";i:9;
    s:12:"Birdweight";s:4:"10KG";
    s:4:"type";s:6:"Animal";
}
可以看出,
*/

【4】序列化对象中的__sleep()魔术方法

          serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。

          此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

          __sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。

魔术方法:
	public array __sleep ( void );
作用:
	对象被序列化时候,先调用此方法,然后执行序列化。
返回值:
	1.返回一个包含对象中所有应被序列化的变量名称的数组。
	2.如果该方法未返回任何内容,则 NULL 被序列化,报 E_NOTICE 级别的错误。
class Bird {
    const wings = 2;
    public    $name;
    protected $age;
    private   $weight;
    public function __construct($name,$age,$weight){
        $this->name = $name;
        $this->age = $age;
        $this->weight = $weight;
    }
    //使用__sleep()魔术方法  自定义序列化行为
    public function __sleep(){
        return ['weight'];#返回对象的私有属性
    }
}
$bigBird = new Bird('Big sparrow',9,'10KG');
#执行序列化,经过__sleep(),会返回特定的值
echo serialize($bigBird);//O:4:"Bird":1:{s:12:"Birdweight";s:4:"10KG";}

【5】file_put_contents保存序列化值到文件

函数用法:
	file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] ) : int
作用:
	将一个字符串写入文件
参数:
	$filename 被写入数据的文件名,不存在会自动创建,默认存在的话内容被覆盖。
	$data 要写入的数据。类型可以是 string,array 或者是 stream 资源
	$flags 
		FILE_USE_INCLUDE_PATH 在 include 目录里搜索 filename
		FILE_APPEND	如果文件 filename 已经存在,追加数据而不是覆盖。
		LOCK_EX	 	在写入时获得一个独占锁。
返回值:
	该函数将返回写入到文件内数据的字节数,失败时返回FALSE
#将上面的代码序列化的值存入文件中
    $bigBird = new Bird('Big sparrow',9,'10KG');
    $ser = serialize($bigBird);
    file_put_contents('Bird.ser', $ser,FILE_APPEND);
    //O:4:"Bird":1:{s:12:"Birdweight";s:4:"10KG";}

【6】反序列化对象中的__wakeup()魔术方法

          unserialize()反序列化函数用于将单一的已序列化的变量转换回 PHP 的值。如果是反序列化后是对象,那么会调用__wakeup()魔术方法。__wakeup()经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。

魔术方法:
	 public __sleep ( void ) : array
作用:
	unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
返回值:
	如果传递的字符串是正确的序列化值,会返回对应的变量值。
	如果传递的字符串不可解序列化,则返回 FALSE,并产生一个E_NOTICE。
class Bird {
    const wings = 2;
    public    $name;
    protected $age;
    private   $weight;
    public function __construct($name,$age,$weight){
        $this->name = $name;
        $this->age = $age;
        $this->weight = $weight;
    }
    //使用__wakeup()魔术方法  定义反序列化后执行调用的方法
    public function __wakeup(){
        echo 'WakeUp WakeUp WakeUp';
    }
}
$bigBird = new Bird('Big sparrow',9,'10KG');
$ser = serialize($bigBird);
$obj = unserialize($ser);//反序列化后成功构造一个新对象,然后调用__wakeup方法执行WakeUp WakeUp WakeUp
var_dump($obj);//打印对象
echo $obj->name;//输出对象属性
/*
WakeUp WakeUp WakeUp

object(Bird)[2]
  public 'name' => string 'Big sparrow' (length=11)
  protected 'age' => int 9
  private 'weight' => string '10KG' (length=4)

Big sparrow
*/

【7】序列化接口Serializable

          这个Serializable,是PHP中预定义的。实现此接口的类将不再支持 sleep() 和 wakeup()。不论何时,只要有实例需要被序列化,serialize 方法都将被调用。当数据被反序列化时,类将被感知并且调用合适的 unserialize() 方法而不是调用构造函数__ construct()。如果需要执行标准的构造器,你应该在这个方法中进行处理。

Serializable {
    abstract public serialize ( void ) : string
    abstract public unserialize ( string $serialized ) : mixed
}

          写一个类实现Serializable接口,然后实现serialize方法和unserialize方法。

class obj implements Serializable {
    private $data;
    public function __construct() {
        $this->data = "My private data";
    }
    #实现接口的方法serialize
    public function serialize() {
        return serialize($this->data);
    }
    #实现接口的方法unserialize
    public function unserialize($data) {
        $this->data = unserialize($data);
    }
    public function getData() {
        return $this->data;
    }
    public function __sleep(){#实现Serializable的接口   __sleep不会被调用
        echo '__sleep()';
    }
    public function __wakup(){#实现Serializable的接口   __wakup不会被调用
        echo '__wakup()';
    }
}
$obj = new obj;
$ser = serialize($obj);
$newobj = unserialize($ser);
var_dump($newobj->getData());//string 'My private data' (length=15)

【8】小结

     序列化和反序列化是一种传输抽象数据的思想。通过定义序列化和反序列化的规则,我们可以实现将PHP中的对象序列化成字节流。在PHP中很序列化用的不多,序列化和反序列化一般用做缓存,比如session缓存,cookie等。

     另外PHP还有另外一种常见方式json去把数组或者对象转化成字符串,也就是用json_encode()json_decode()函数,不仅转化后,数据很直观,而且这种方法更迅速,听说大概快两三倍。

 类似资料: