• PHP 对象序列化


    1. 对象序列化

    1.1 serialize() 和 unserialize()

    所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。

    为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。 如果要想在另外一个文件中反序列化一个对象,这个对象的类必须在反序列化之前定义,可以通过包含一个定义该类的文件或使用函数spl_autoload_register()来实现。

    <?php
    // classa.inc:
      
      class A {
          public $one = 1;
        
          public function show_one() {
    	  echo $this->one;
          }
      }
      
    // page1.php:
    
      include("classa.inc");
      
      $a = new A;
      $s = serialize($a);
      // 把变量$s保存起来以便文件page2.php能够读到
      file_put_contents('store', $s);
    
    // page2.php:
      
      // 要正确反序列化,必须包含下面一个文件
      include("classa.inc");
    
      $s = file_get_contents('store');
      $a = unserialize($s);
    
      // 现在可以使用对象$a里面的函数 show_one()
      $a->show_one();
    ?>
    

    可以在对象上使用 __sleep()__wakeup() 方法对序列化/反序列化事件挂载钩子。 使用 __sleep() 也能够让你仅序列化对象的某些属性

    2.魔术方法

    2.1 __sleep()__wakeup()

    public __sleep(): array
    
    public __wakeup(): void
    

    serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 null 被序列化,并产生一个 E_NOTICE 级别的错误。

    注意:
    
    __sleep() 不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代
    

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

    与之相反,unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。

    __wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。

    示例 #1 Sleep 和 wakeup

    <?php
    class Connection 
    {
        protected $link;
        private $server, $username, $password, $db;
        
        public function __construct($server, $username, $password, $db)
        {
    	$this->server = $server;
    	$this->username = $username;
    	$this->password = $password;
    	$this->db = $db;
    	$this->connect();
        }
        
        private function connect()
        {
    	$this->link = mysql_connect($this->server, $this->username, $this->password);
    	mysql_select_db($this->db, $this->link);
        }
        
        public function __sleep()
        {
    	return array('server', 'username', 'password', 'db');
        }
        
        public function __wakeup()
        {
    	$this->connect();
        }
    }
    ?>
    

    2.2 __serialize()__unserialize()

    注意:
    此特性自 PHP 7.4.0 起可用。  
    
    public __serialize(): array
    public __unserialize(array $data): void
    

    serialize() 函数会检查类中是否存在一个魔术方法 __serialize()。如果存在,该方法将在任何序列化之前优先执行。它必须以一个代表对象序列化形式的 键/值 成对的关联数组形式来返回,如果没有返回数组,将会抛出一个 TypeError 错误

    注意:
    如果类中同时定义了 __serialize() 和 __sleep() 两个魔术方法,则只有 __serialize() 方法会被调用。 __sleep() 方法会被忽略掉。<br>如果对象实现了 Serializable 接口,接口的 serialize() 方法会被忽略,做为代替类中的 __serialize() 方法会被调用。
    如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法,则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。
    

    示例 #2 序列化和反序列化

    <?php
    class Connection
    {
        protected $link;
        private $dsn, $username, $password;
    
        public function __construct($dsn, $username, $password)
        {
    	$this->dsn = $dsn;
    	$this->username = $username;
    	$this->password = $password;
    	$this->connect();
        }
    
        private function connect()
        {
    	$this->link = new PDO($this->dsn, $this->username, $this->password);
        }
    
        public function __serialize(): array
        {
    	return [
    	  'dsn' => $this->dsn,
    	  'user' => $this->username,
    	  'pass' => $this->password,
    	];
        }
    
        public function __unserialize(array $data): void
        {
    	$this->dsn = $data['dsn'];
    	$this->username = $data['user'];
    	$this->password = $data['pass'];
    
    	$this->connect();
        }
    }?>
    

    3. 序列化接口

    3.1 简介

    序列化接口文档 - 详情

    自定义序列化的接口。
    实现此接口的类将不再支持 __sleep()__wakeup()。不论何时,只要有实例需要被序列化,serialize 方法都将被调用。它将不会调用 __destruct() 或有其他影响,除非程序化地调用此方法。当数据被反序列化时,类将被感知并且调用合适的 unserialize() 方法而不是调用 __construct()。如果需要执行标准的构造器,你应该在这个方法中进行处理。

    3.2 接口摘要

    class Serializable {
    	/* 方法 */
    	abstract public serialize(): string
    	abstract public unserialize(string $serialized): mixed
    }
    

    示例 #1 Basic usage

    <?php
    class obj implements Serializable {
        private $data;
        public function __construct() {
    	$this->data = "My private data";
        }
        public function serialize() {
    	return serialize($this->data);
        }
        public function unserialize($data) {
    	$this->data = unserialize($data);
        }
        public function getData() {
    	return $this->data;
        }
    }
    
    $obj = new obj;
    $ser = serialize($obj);
    
    $newobj = unserialize($ser);
    
    var_dump($newobj->getData());
    ?>
    

    以上例程的输出类似于:

    string(15) "My private data"
    

    示例 #2 Here's an example how to un-, serialize more than one property:

    class Example implements Serializable
    {
        protected $property1;
        protected $property2;
        protected $property3;
    
        public function __construct($property1, $property2, $property3)
        {
    	$this->property1 = $property1;
    	$this->property2 = $property2;
    	$this->property3 = $property3;
        }
    
        public function serialize()
        {
    	return serialize([
    	    $this->property1,
    	    $this->property2,
    	    $this->property3,
    	]);
        }
    
        public function unserialize($data)
        {
    	list(
    	    $this->property1,
    	    $this->property2,
    	    $this->property3
    	) = unserialize($data);
        }
    
    }
    

    示例 #3 Serializing child and parent classes:

    <?php
    class MyClass implements Serializable {
        private $data;
       
        public function __construct($data) {
    	$this->data = $data;
        }
       
        public function getData() {
    	return $this->data;
        }
       
        public function serialize() {
    	echo "Serializing MyClass...
    ";
    	return serialize($this->data);
        }
       
        public function unserialize($data) {
    	echo "Unserializing MyClass...
    ";
    	$this->data = unserialize($data);
        }
    }
    
    class MyChildClass extends MyClass {
        private $id;
        private $name;
       
        public function __construct($id, $name, $data) {
    	parent::__construct($data);
    	$this->id = $id;
    	$this->name = $name;
        }
       
        public function serialize() {
    	echo "Serializing MyChildClass...
    ";
    	return serialize(
    	    array(
    		'id' => $this->id,
    		'name' => $this->name,
    		'parentData' => parent::serialize()
    	    )
    	);
        }
       
        public function unserialize($data) {
    	echo "Unserializing MyChildClass...
    ";
    	$data = unserialize($data);
           
    	$this->id = $data['id'];
    	$this->name = $data['name'];
    	parent::unserialize($data['parentData']);
        }
       
        public function getId() {
    	return $this->id;
        }
       
        public function getName() {
    	return $this->name;
        }
    }
    
    $obj = new MyChildClass(15, 'My class name', 'My data');
    
    $serial = serialize($obj);
    $newObject = unserialize($serial);
    
    echo $newObject->getId() . PHP_EOL;
    echo $newObject->getName() . PHP_EOL;
    echo $newObject->getData() . PHP_EOL;
    
    ?>
    

    This will output:

    Serializing MyChildClass...
    Serializing MyClass...
    Unserializing MyChildClass...
    Unserializing MyClass...
    15
    My class name
    My data
  • 相关阅读:
    c#正则表达式应用实例
    C# 中堆栈,堆,值类型,引用类型的理解 (摘抄)
    c#用正则表达式获得指定开始和结束字符串中间的一段文本
    asp.net c#截取指定字符串函数
    <收藏>提高Web性能的14条法则(详细版)
    利用Anthem.net 实现前台javascript调用服务器端c#函数 及流程分析
    Anthem.net
    jQuery animate(滑块滑动)
    .NET使用母版页后,控件名称自动生成导致js无法正常操作.net控件的问题
    Cocos2dx跨平台Android环境配置
  • 原文地址:https://www.cnblogs.com/zakun/p/php-serialize.html
Copyright © 2020-2023  润新知