使用PHP将嵌套对象序列化/反序列化为JSON类型


Serialize/deserialize nested objects to JSON with type in PHP

我有扩展抽象类的类。我需要通过字符串(最好是JSON)创建这些类的实例。

许多对象是嵌套的,许多属性是私有的。我需要一种方法:

  1. 创建一个完整对象的JSON字符串(带有私有属性和嵌套对象-带有它们的私有属性)
  2. 从JSON字符串创建一个新的Object,其中包含正确的类型和所有嵌套对象

我想它需要递归。

如果我只是将对象强制转换为数组,那么我使用的名称空间最终看起来就像垃圾。

我正在考虑编写一个解析器,在JSON字符串中标记类,然后为每个类硬编码一个工厂函数,但这需要很多时间。

我建议使用jms序列化程序:http://jmsyst.com/libs/serializer易于使用、可配置并支持您要求的所有功能。

我建议您使用php的序列化函数

在这种情况下,最好使用此函数,因为它是为此目的而存在的:您可以将序列化的字符串存储在任何您想要的位置,在取消序列化后,您将返回具有所有属性的原始PHP对象

使用JSON,正如您所说,您将不知道对象是什么类(除非您将其手动存储为字符串),当然,还会出现与私有属性

相关的所有问题

有三种方法:JSON、Serialize和var_export。

使用JSON,它只能处理stdClass的对象,但它很容易阅读,并且可以在PHP之外使用。

Serialize适用于stdClass以外的类实例,但它可能很难读取,只能由PHP使用。http://php.net/manual/en/function.serialize.php

var_export输出PHP代码来创建对象(所以你可以把它写到一个PHP文件中),它很容易阅读,但不能在PHP之外使用。对象将需要具有set state方法。http://php.net/manual/en/function.var-export.php

您可以做的一件事是在每个要序列化和取消序列化的类中使用魔术方法,方法是'__serialize()'和'__unserialize(array$data)',__serializ返回一个具有自己对象属性的关联数组就像getter,__unserilize根据数组中的数据设置对象的状态就像setter!。下面展示了一个我用来解决这个问题的例子,这是一个使用OOP的例子。

这就像项目的主体,它所做的基本上是构建一个对象数组,这个对象包含一个其他对象数组,等等。然后序列化所有封装的对象,然后使用__unserialize取消序列化创建同一实例的另一个对象,并获得正确的所有信息就在这里。注:cargarArchivo.php类位于末尾,该类用于加载"provincias=>就像美国的一个州一样。查看文件的costaRica.xml&json‘信息从这个文件加载到gitHub存储库。https://github.com/Gabriel-Barboza-Carvajal/Fetch-API-PHP-JSON/blob/master/servidor.php

include_once './modelo/division.php';
        include_once './modelo/canton.php';
        include_once './modelo/distrito.php';
        include_once './modelo/provincia.php';
        include_once './modelo/division_total.php';
        include_once './cargarArchivo.php';
       
        $divi=new division_total();
        $divi->provincias= cargarArchivo::devolverXMLCostaRica();
        //serializamos la informacion obtenida.
        $data = $divi->__serialize();
        
        //deserealizamos.
        $diviDeserea=new division_total();
        
        $diviDeserea->__unserialize($data);
        
abstract class division {
    private $numero, $nombre;
    
    public function __construct($numero, $nombre) {
        $this->numero = $numero;
        $this->nombre = $nombre;
    }

    public function __destruct() {
//        echo "<br>destruyendo obj general<br>";
    }
    public function getNumero() {
        return $this->numero;
    }
    public function getNombre() {
        return $this->nombre;
    }
    public function setNumero($numero) {
        $this->numero = $numero;
        return $this;
    }
    public function setNombre($nombre) {
        $this->nombre = $nombre;
        return $this;
    }
    
    abstract public function __serialize():array;
    abstract public function __unserialize(array $data):void;
    abstract public function __toString():string;
}
And the other classes the same like this...

class provincia extends division {
    public $cantones;
    public function __construct($num, $nom, $cant=null) {
        parent::__construct($num, $nom);
        $this->cantones = $cant;
    }
     public function __serialize(): array {
        return[
            'nombre' => $this->getNombre(),
            'número' => $this->getNumero(),
            'cantones' => $this->serializarCantones()
        ];
    }
    public function serializarCantones(): array {
        $todos = array();
        for ($index = 0; $index < count($this->cantones); $index++) {
            array_push($todos, ($this->cantones[$index])->__serialize());
        }
        return $todos;
    }
    public function __unserialize(array $data): void {
        $this->setNombre($data['nombre']);
        $this->setNumero($data['número']);
        $this->unserializarCantones($data);
    }
    
    public function unserializarCantones(array $data): void {
        $dis = $data['cantones'];
        $cont=0;
        foreach ($dis as $value) {
            $this->cantones[$cont] = new canton('', '');
            $this->cantones[$cont]->__unserialize($value);
            $cont+=1;
        }
    }
    public function __toString(): string {
        $str='';
        $str = '<br>' . $this->getNombre() . "|" . $this->getNumero() . '<br>';
        foreach ($this->cantones as $value) {
            $str .=$value->__toString();
        }
        return $str;
    }
}
class canton extends division {
    public $distritos;
    public function __construct($num, $nom, $distro = array()) {
        parent::__construct($num, $nom);
        $this->distritos = $distro;
    }
    public function agregarCantones($distritos) {
        $this->distritos = $distritos;
    }
    
    public function __serialize(): array {
        return[
            'nombre' => $this->getNombre(),
            'número' => $this->getNumero(),
            'distritos' => $this->serializarDistritos()
        ];
    }
    public function serializarDistritos(): array {
        $todos = array();
        for ($index = 0; $index < count($this->distritos); $index++) {
            array_push($todos, ($this->distritos[$index])->__serialize());
        }
        return $todos;
    }
    public function unserializarDistritos(array $data): void {
        $dis = $data['distritos'];
        $cont=0;
        foreach ($dis as $value) {
            $this->distritos[$cont] = new distrito('', '');
            $this->distritos[$cont]->__unserialize($value);
            $cont+=1;
        }
    }
    public function __unserialize(array $data): void {
        $this->setNombre($data['nombre']);
        $this->setNumero($data['número']);
        $this->unserializarDistritos($data);
    }
    public function __toString(): string {
        $str='';
        $str = '<br>' . $this->getNombre() . "|" . $this->getNumero() . '<br>';
        foreach ($this->distritos as $value) {
            $str .= $value->__toString();
        }
        return $str;
    }
}


class distrito extends division {
    private $secuencia;
    public function __construct($num = '', $nom = '', $sec = null) {
        parent::__construct($num, $nom);
        $this->secuencia = $sec;
    }
    public function getSecuencia() {
        return $this->secuencia;
    }
    public function setSecuencia($secuencia) {
        $this->secuencia = $secuencia;
        return $this;
    }
    public function __serialize(): array {
        return [
            'nombre'=> $this->getNombre(),
            'número'=> $this->getNumero(),
            'secuencia'=> $this->getSecuencia()
            ];
    }
    public function __unserialize(array $data): void {
        $this->secuencia=$data['secuencia'];
        $this->setNombre($data['nombre']);
        $this->setNumero($data['número']);
    }
    public function __toString(): string {
        $str='';
        $str= $this->getNombre() . ' , ' .$this->getNumero() . ' , ' . $this->getSecuencia();
        return $str;
    }
}
class division_total extends division{
    
    function __construct() {
        parent::__construct('0', 'Costa Rica');
    }
      public function __serialize(): array {
        return[
            'nombre' => $this->getNombre(),
            'número' => $this->getNumero(),
            'provincias' => $this->serializarProvincias()
        ];
    }
    public function serializarProvincias(): array {
        $todos = array();
        for ($index = 0; $index < count($this->provincias); $index++) {
            array_push($todos, ($this->provincias[$index])->__serialize());
        }
        return $todos;
    }
    public function __unserialize(array $data): void {
        $this->setNombre($data['nombre']);
        $this->setNumero($data['número']);
        $this->unserializarProvincias($data);
    }
    
    public function unserializarProvincias(array $data): void {
        $dis = $data['provincias'];
        $cont=0;
        foreach ($dis as $value) {
            $this->provincias[$cont] = new provincia('', '');
            $this->provincias[$cont]->__unserialize($value);
            $cont+=1;
        }
    }
    public function __toString(): string {
        $str='';
        $str = '<br>' . $this->getNombre() . "|" . $this->getNumero() . '<br>';
        foreach ($this->provincias as $value) {
            $str .=$value->__toString();
        }
        return $str;
    }
    public $provincias = array();
    
  
}
class cargarArchivo {
    public function __construct() {
        
    }
    static public function devolverXMLCostaRica() {
        libxml_use_internal_errors(true);
        $xml = simplexml_load_file('CostaRica.xml');
        if ($xml === false) {
            echo "Failed loading XML: ";
            foreach (libxml_get_errors() as $error) {
                echo "<br>", $error->message;
            }
        } else {
//            print_r($xml);
            //recorremos las provincias
            $divisionPolitica= array();
            foreach ($xml->children() as $data)
            {
                $nombre= $data['nombre'];
                $numero= $data['número'];
                $provin=new provincia($numero, $nombre);
                $cantones=array();
                array_push($divisionPolitica,$provin);//agregamos la provincia a la division politica.
                //recorremos el numero de cantones que tiene la provincia
                for ($index = 0; $index < $data->cantón->count(); $index++) {                    
                    $nomDistrCanton=$data->cantón[$index]['nombre'];
                    $numDistrCanton=$data->cantón[$index]->count();
                    $canton=new canton($numDistrCanton, $nomDistrCanton);
                    array_push($cantones,$canton);//agregamos un canton a la provincia
                    //ahora ocupamos recorrer todos los distritos que maneja este primer canton
                    $x=$data->cantón[$index];
                    $distritos=array();
                    for ($index1 = 0; $index1 < $data->cantón[$index]->count(); $index1++) {
                         $nom=$data->cantón[$index]->distrito['nombre'];
                         $num=$data->cantón[$index]->distrito['número'];
                         $sec=$data->cantón[$index]->distrito['secuencia'];
                        $distri=new distrito($num, $nom, $sec);
                        array_push($distritos,$distri);
                    }
                    $canton->distritos=$distritos;
                    $provin->cantones=$cantones;
                }
                
            }
            
            
            }
            
            
        
        return $divisionPolitica;
    }