【问题标题】:PHP Serialize object treePHP序列化对象树
【发布时间】:2018-01-09 08:27:13
【问题描述】:

我有一个如下所示的对象树,我需要对其进行序列化并存储在文件系统中。我需要具有所有类属性的完整层次结构,稍后我将反序列化并恢复类层次结构。

class X implements \Serializable {

  private $x1;

    public function serialize() {
            return serialize(get_class_vars(get_class($this)));
    }

    public function unserialize($data) {
            $values = unserialize($data);
            foreach ($values as $key => $value) {
                    $this->$key = $value;
            }
    }
}

class A implements \Serializable {

  private $a1;
  private $a2;
  // type of a3 is class X!
  protected $a3;

    public function serialize() {
            return serialize(get_class_vars(get_class($this)));
    }

    public function unserialize($data) {
            $values = unserialize($data);
            foreach ($values as $key => $value) {
                    $this->$key = $value;
            }
    }
}

class B extends A implements \Serializable {

  private $b1;
  private $b2;

    public function serialize() {
    //  $base = parent::serialize();
            return serialize(get_class_vars(get_class($this)));
    }

    public function unserialize($data) {
            $values = unserialize($data);
            foreach ($values as $key => $value) {
                    $this->$key = $value;
            }
    }
}


class C extends A implements \Serializable {

  private $c1;
  private $c2;

    public function serialize() {
    //  $base = parent::serialize();
            return serialize(get_class_vars(get_class($this)));
    }

    public function unserialize($data) {
            $values = unserialize($data);
            foreach ($values as $key => $value) {
                    $this->$key = $value;
            }
    }
}

子类可以自己序列化,但是对于基类我不知道如何组合序列化的数据。此外,我从文件系统获取序列化数据,但我不知道我会得到哪个子类。 PHP 的 unserialize() 是否创建了正确的类实例?它还应该初始化基类 A。

我该如何解决?

也许我可以使用 var_dump() 输出,但如何将其存储到变量中?

【问题讨论】:

    标签: php oop serialization


    【解决方案1】:

    这就是我推荐的序列化对象的方式:

    class Color implements \Serializable
    {
        private $Name;
        private $Type;
    
        public function __construct(string $Name, int $Type)
        {
            $this->Name = $Name;
            $this->Type = $Type;
        }
    
        public function serialize()
        {
            $Props['Name'] = $this->Name;
            $Props['Type'] = $this->Type;
            return serialize($Props);
        }
    
        public function unserialize($Data)
        {
            list($this->Name, $this->Type) = unserialize($Data);
        }
    }
    
    class Blue extends Color
    {
        private $Intensity;
    
        public function __construct()
        {
            parent::__construct('Blue', 10);
            $this->Intensity = 90;
        }
    
        public function serialize()
        {
            $Props['parent'] = parent::serialize();
            $Props['Intensity'] = $this->Intensity;
            return serialize($Props);
        }
    
        public function unserialize($Data)
        {
            $Obj = unserialize($Data);
            parent::unserialize($Obj['parent']);
            $this->Intensity = $Obj['Intensity'];
        }
    }
    

    您传递给 serialize() 函数的任何对象都是您将返回(作为字符串)到 unserialize() 的对象。如果你走自己的路,那么你可以在 trait 中实现 serialize()/unserialize() 函数,而 get_object_vars() 将适用于私有变量。

    【讨论】:

      【解决方案2】:

      我已经在每个受影响的类中实现了 serialize() 和 unserialize(),如下所示:

              public function serialize() {
      
                  $res = array();
      
                  $reflect = new \ReflectionClass(__CLASS__);
                  $propList = $reflect->getProperties();
      
                  foreach($propList as $prop) {
                          if ($prop->class != __CLASS__) {
                                  continue; // visible properties of base clases
                          }
      
                          $name = $prop->name;
                          $res[$name . ":" . __CLASS__] = serialize($this->$name);
                  }
      
                  if (method_exists(get_parent_class(__CLASS__), "serialize")) {
                          $base = unserialize(parent::serialize());
                          $res = array_merge($res, $base);
                  }
      
                  return serialize($res);
          }
      
          public function unserialize($data) {
      
                  $values = unserialize($data);
                  foreach ($values as $key => $value) {
      
                          // key contains propertyName:className
                          $prop = explode(":", $key);
                          if ($prop[1] != __CLASS__) {
                                  continue;
                          }
      
                          $this->$prop[0] = unserialize($value);
                  }
      
                  // call base class
                  if (method_exists(get_parent_class(__CLASS__), "unserialize")) {
                          parent::unserialize($data);
                  }
          }
      

      也许有一种解决方案可以将此功能添加到基类以防止代码复制。它应该适用于简单的属性、数组和对象,也适用于具有多级父类的大型对象树。

      【讨论】:

      • 这段代码似乎有类引用的问题。有时结果包含 r:147,它是对对象的引用,也存储在另一个变量中。 unserialize() 无法处理。也许您可以将对象内容复制到新对象中以防止引用。
      猜你喜欢
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多