TransWikia.com

Serialize/deserialize nested objects to JSON with type in PHP

Stack Overflow Asked on December 20, 2021

I have classes that extends an abstract class. I need to create instances of these classes through a string – preferably JSON.

Many of the objects are nested, and many properties are private. I need a way to:

  1. Create a JSON string of the complete object (with private properties and nested objects – with their private properties).
  2. Create a new Object from a JSON string, with the correct type and all nested objects.

I guess it needs to be recursive.

I’m using namespaces that end up looking like crap if I just cast the object to an array.

I’m thinking of writing a parser, label the classes in my JSON strings and then hardcode a factory function for every class, but that would take a lot of time.

4 Answers

One thing thay you can do is using the magic methods in every class that you want to serialize and unserialize , the methods are '__serialize()' and '__unserialize(array $data)', __serialize return a associative array with properties of the own object is like the getter, and __unserialize set the state of the object base on the data from the array is like the setter!. Below a show a example that i used to solve that, is a example using OOP.

this is like the main of the project and what it does is basically build an array of objects and this objects contain an array of other objects and so on. then serialize all the wrapped object and then unserialize creating another object of the same instance using __unserialize and get all the information correct here it is. NOTE:The class cargarArchivo.php is at the end, that class is use for load the information of the Costa Rica political division of the 'provincias => like a state in US.' and the tows of the provincias with the data asociative to it. LOOK TO THE FILE 'costaRica.xml & costaRica.json'the information is loaded from this files look to the gitHub repository. 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;
    }

Answered by Gabriel Barboza on December 20, 2021

There are three methods for doing this: JSON, Serialize, and var_export.

With JSON, it will only work with objects of stdClass, but it's easy to read and can be used outside of PHP.

Serialize works with instances of classes other than stdClass, but it can be difficult to read and can only be used by PHP. http://php.net/manual/en/function.serialize.php

var_export outputs the PHP code to create the object (so you'd write it to a PHP file), it's very easy to read but can't be used outside PHP. The objects will need to have the set state method. http://php.net/manual/en/function.var-export.php

Answered by Ryan Jenkin on December 20, 2021

I suggest using the jms serializer: http://jmsyst.com/libs/serializer Easy to use, configuarble and supports all the features you requested.

Answered by Atan on December 20, 2021

I suggest you to use php's serialize function

In cases like this it's better to use this function because it exists for this purpose: you can store the serialized string wherever you want and after unserializing it you will get back the original PHP object with all the properties

With JSON, as you said, you'll have no clue of what class the object was (unless you store it manually as a string) and of course there will be all the problems related to the private properties

Answered by Moppo on December 20, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP