7 Stimmen

Serialisieren/Deserialisieren von PHP-Objektgraphen zu JSON

Ich wollte einen kompletten PHP-Objektgraphen in eine JSON-Zeichenfolgen-Repräsentation serialisieren und ihn wieder in einen identischen PHP-Objektgraphen deserialisieren.

Hier finden Sie eine Zusammenfassung der von mir in Betracht gezogenen Optionen und Gründe, warum sie für mich nicht funktionieren:

  • serialize() tut nicht, was ich möchte, da es ein PHP-spezifisches Format verwendet. Ich möchte ein Format, das von den meisten Sprachen weitgehend unterstützt wird und menschenlesbar/editierbar ist.

  • json_encode() tut nicht, was ich möchte, weil es nur einfache Werte und Arrays, nicht jedoch Objekte unterstützt. (Ich verwende dies tatsächlich in meiner Implementierung, siehe unten.)

  • var_export() behandelt keine zirkulären Referenzen und tut nicht, was ich möchte (siehe oben). (Beachten Sie, dass meine aktuelle Implementierung auch keine zirkulären Referenzen behandelt - siehe Kommentare und Antworten unten zur Klärung dieses Problems.)

  • Sebastian Bergmanns Object Freezer ist eine gute Implementierung, erfüllt jedoch nicht meine Anforderungen - er verwendet eine sehr lange Form und verlässt sich darauf, die serialisierten Objekte mit GUIDs zu füllen.

  • Serialized tut nicht, was ich möchte - es führt keine tatsächliche Serialisierung durch, sondern analysiert die Ausgabe von serialize() und erstellt eine andere Repräsentation, z. B. XML, kann aber diese Repräsentation nicht wieder analysieren. (es unterstützt auch kein JSON - XML ist sehr lang und entspricht nicht meinen Anforderungen.)

Ich habe jetzt eine funktionierende Implementierung zum Teilen:

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

Die JSON-Repräsentation des Objektgraphen sieht so aus:

{
    "#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
}

Dieser Ansatz ist darauf ausgelegt, für eine reine Baumstruktur-Aggregation zu funktionieren - zirkuläre Referenzen sind nicht erlaubt, ebenso wenig wie mehrfache Verweise auf dieselben Objekte. Mit anderen Worten, dies ist nicht wie z. B. serialize() und unserialize() für beliebige PHP-Objektgraphen geeignet.

In meinem ursprünglichen Ansatz verwendete ich eine serialisierte Form, die im Wesentlichen eine Basis-0-Liste von Objekten war. Das erste Objekt in der Liste (Nummer 0) ist die Wurzel des serialisierten Objektgraphen, alle anderen Objekte werden in der Reihenfolge gespeichert, in der sie gefunden wurden.

In der aktuellen Implementierung ähnelt die JSON-Repräsentation der Originalbaumstruktur soweit dies möglich ist, was es ermöglicht, tatsächlich mit der JSON-Repräsentation eines Objektgraphen in JavaScript zu arbeiten. Die einzige Abweichung ist das magische #type Eigenschaft (mit # versehen, um Kollisionen mit Eigenschaftsnamen zu verhindern) und der #hash "Typ", der verwendet wird, um array-Typ-Hashes (gespeichert als JSON-Objekte) von regulären array-Typ-Arrays (gespeichert als JSON-Arrays) zu unterscheiden.


Ich lasse diese Notizen zur früheren Version hier aus historischen Gründen stehen.

Zirkuläre Verweise werden einfach behandelt, indem niemals verschachtelte Objekte innerhalb der serialisierten Repräsentation jedes Objekts gespeichert werden - stattdessen wird jeder Objektverweis als JSON-Objekt mit dem Objektindex gespeichert - z. B. {"__oref":2} ist ein Verweis auf das Objekt mit dem Index 2 in der Objektliste.

Ich habe ein Problem mit Array-Verweisen in meiner Implementierung - wenn ich ein var_dump() im Code platziere, der Verweise auf Objekte im Array wiederherstellt, werden sie gefüllt, aber irgendwann wird das Array kopiert und am Ende erhalten Sie die leere Kopie. Ich habe versucht, überall im Code & Zeichen zu platzieren, aber unabhängig davon, wo ich die Referenz weitergebe, ist das Endergebnis ein leeres Array.

1voto

mindplay.dk Punkte 6764

Das fertige Skript (oben gepostet) entspricht genau meinen Anforderungen:

  • Serialisieren und Deserialisieren eines gesamten Aggregats.

  • Eine JSON-Repräsentation, die der originalen Datenstruktur sehr nahe kommt.

  • Die Datenstruktur nicht mit dynamisch generierten Schlüsseln oder anderen Daten verunreinigen.

Es behandelt keine zirkulären Referenzen. Wie in einem oben genannten Kommentar festgestellt wurde, gibt es keinen richtigen Weg, um zirkuläre Referenzen oder mehrfache Referenzen auf dasselbe Objekt zu speichern, da diese alle gleich sind. Mit diesem Wissen entschied ich mich dafür, dass mein Objektgraph ein regulärer Baum sein muss, und akzeptierte diese Einschränkung als "eine gute Sache".

Aktualisierung: Der Output kann jetzt mit Einrückungen, Zeilenumbrüchen und Leerzeichen formatiert werden - für mich war es wichtig, eine menschenlesbare (und versionskontrollfreundliche) Darstellung für meine Zwecke zu haben. (Das Formatieren kann bei Bedarf aktiviert oder deaktiviert werden.)

0voto

dnshio Punkte 864

Ich weiß nicht, ob das ist, wonach Sie suchen, aber wenn Sie nur an den öffentlichen Eigenschaften eines Objekts interessiert sind, wird get_object_vars($obj) den Trick tun.

Gibt aus:

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

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

Die obige Methode ist nutzlos für den Zugriff auf Funktionsverweise und private Variablen, aber Sie könnten dies möglicherweise in Verbindung mit etwas zusätzlichem Code verwenden, um das zu erstellen, was Sie möchten.

Dinesh.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X