PHP Serialize object tree

2020-03-30 01:43发布

I have an object tree like the following, which I need to serialize and store on the filesystem. I need the full hierarchy with all class properties and later I will unserialize and restore the class hierarchy.

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;
            }
    }
}

The subclasses can serialize itself, but for the base class I don't know, how I can combine the serialized data. Furthermore I get serialized data from the filesystem, but I don't know, which subclass I will get. Does PHP's unserialize() create the right class instance? It should also initialize the base class A.

How can I solve that?

Maybe I can use the var_dump() output, but how I can store it into a variable?

2条回答
Melony?
2楼-- · 2020-03-30 02:20

This is how I would recommend serializing objects:

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'];
    }
}

Whichever object you pass in to the serialize() function is the object you will get back (as a string) to unserialize(). If you go your route, then you can implement the serialize()/unserialize() functions inside a trait and get_object_vars() will work properly for private variables.

查看更多
倾城 Initia
3楼-- · 2020-03-30 02:28

I have implemented serialize() and unserialize() in every affected class like this:

        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);
            }
    }

Maybe there is a solution to add this functionality to a base class to prevent code copies. It should work with simple properties, arrays and objects also for large object trees with multiple levels of parent classes.

查看更多
登录 后发表回答