Serialize / unserialize PHP object-graph su JSON

Volevo serializzare un completo object-graph PHP in una rappresentazione di string JSON e digitalizzarlo di nuovo a un identico object-grafico PHP.

Ecco un riepilogo delle opzioni che ho considerato e le ragioni per cui non funzionano per me:

Ora ho un'implementazione funzionante da condividere:

https://github.com/mindplay-dk/jsonfreeze

La rappresentazione JSON del grafico ad oggetti ha il seguente aspetto:

 { "#type": "Order", "orderNo": 123, "lines": [{ "#type": "OrderLine", "item": "milk \"fuzz\"", "amount": 3, "options": null }, { "#type": "OrderLine", "item": "cookies", "amount": 7, "options": { "#type": "#hash", "flavor": "chocolate", "weight": "1\/2 lb" } }], "paid": true } 

Questo approccio è progettato per funzionare con un aggregato di struttura ad tree puro: non sono consentiti riferimenti circolari, né riferimenti multipli agli stessi oggetti. In altre parole, questo non è general-purpose come ad esempio serialize() e unserialize() quale function per qualsiasi object grafico PHP.

Nel mio approccio iniziale ho usato un module serializzato che era essenzialmente un elenco di oggetti base 0. Il primo object nella list (numero 0) è la radice del grafo degli oggetti serializzato, tutti gli altri oggetti sono memorizzati nell'ordine in cui sono stati trovati.

Nell'implementazione corrente, la rappresentazione JSON assomiglia alla struttura ad tree originale nella misura in cui ciò è ansible, rendendo ansible lavorare effettivamente con la rappresentazione JSON di un object grafico in JavaScript. L'unica deviazione è la properties; #type magica (preceduta da # per evitare la collisione con nomi di properties;) e il #hash "tipo", usato per distinguere gli hash di tipo arrays (memorizzati come oggetti JSON) da arrays tipi di arrays regolari (memorizzati come matrici JSON).


Lascio queste note sulla versione precedente qui per scopi storici.

I riferimenti circolari sono gestiti semplicemente non memorizzando mai oggetti nidificati all'interno della rappresentazione serializzata di ciascun object – invece, qualsiasi riferimento all'object viene memorizzato come object JSON con l'indice-object – ad esempio {"__oref":2} è un riferimento al object con indice 2 nella list degli oggetti.

Sto riscontrando un problema con i riferimenti arrays nella mia implementazione – quando var_dump () all'interno del codice che ripristina i riferimenti agli oggetti nell'arrays, vengono popolati, ma a un certo punto l'arrays viene copiato e si finisce con la copia vuota. Ho provato a mettere & caratteri ovunque nel codice, ma indipendentemente da where passo per riferimento, il risultato finale è un arrays vuoto.

Lo script finito (pubblicato sopra) soddisfa i miei precisi requisiti:

  • Serializza e unserializza un integer aggregato.

  • Hanno una rappresentazione JSON che ricorda da vicino la struttura dei dati originale.

  • Non inquinare la struttura dei dati con chiavi generate dynamicmente o altri dati.

Non gestisce riferimenti circolari. Come sottolineato in un commento sopra, non esiste un modo giusto per memorizzare riferimenti circolari o riferimenti multipli allo stesso object, poiché sono tutti uguali. Comprendendo questo, ho deciso che il mio object-grafico deve essere un tree regolare, e ho accettato questa limitazione come "una buona cosa".

aggiornamento : l'output può ora essere formattato con rientro, newline e spazi vuoti: per me è stato importnte avere una rappresentazione leggibile dall'uomo (e compatibile con i sorgenti) per i miei scopi. (La formattazione può essere abilitata o disabilitata secondo necessità.)

Non so se questo è ciò che cerchi, ma se sei interessato solo a get le properties; pubbliche di un object, get_object_vars ($ obj) farà il trucco.

 <?php class foo { public $fname = "John"; public $sname = "Doe"; private $status = null; static $type = "person"; } $obj = new foo; print_r( (get_object_vars($obj)) ); print json_encode(get_object_vars($obj)); ?> 

Produrrà:

Array ([fname] => John [sname] => Doe)

{ "Fname": "John", "sname": "Doe"}

Il metodo di cui sopra è inutile per accedere ai riferimenti alle funzioni e alle variables private, ma potresti essere in grado di usarlo insieme ad un altro codice per abbattere ciò che vuoi.

Dinesh.