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:
serialize()
non fa quello che voglio, perché usa un formato specifico per PHP. Voglio un formato ampiamente supportto dalla maggior parte delle lingue e leggibile / modificabile.
json_encode()
non fa quello che voglio, perché fa solo valori semplici e matrici, non oggetti. (In realtà sto usando questo nella mia implementazione, vedi sotto).
var_export()
non gestisce i riferimenti circolari e non fa ciò che voglio (vedi sopra). (nota che la mia attuale implementazione non gestisce nemless riferimenti circolari – vedi i commenti e rispondi di seguito per chiarimenti su questo problema).
Object Freezer di Sebastian Bergmann è una buona implementazione, ma non fa quello che voglio io: usa una forma molto lunga e fa affidamento sul riempimento di oggetti serializzati con GUID.
Serializzato non fa ciò che voglio – in realtà non esegue la serializzazione, analizza l'output di serialize()
e produce una rappresentazione diversa, ad esempio XML, ma non è in grado di analizzare quella rappresentazione. (Inoltre non support JSON – XML è una forma molto lunga, e non è quello che voglio.)
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.