PHP序列化对象树

时间:2017-08-02 08:19:13

标签: php oop serialization

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

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()输出,但是如何将它存储到变量中呢?

2 个答案:

答案 0 :(得分: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()函数的对象是您将返回(作为字符串)取消序列化()的对象。如果你走你的路线,那么你可以在trait中实现serialize()/ unserialize()函数,get_object_vars()将适用于私有变量。

答案 1 :(得分:0)

我已在每个受影响的类中实现了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);
            }
    }

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