Wie verschachtelte Arrays mit ArrayObject zu deaktivieren?

8

ideone

Beispielcode:

%Vor%

Ausgabe

%Vor%

Sie bemerken, dass $a['b']['c'] immer noch da ist, auch nach dem Unscharfschalten. Ich würde erwarten, dass $a nur noch den einen Wert hat ( b ).

In meiner aktuellen App erhalte ich folgende Warnung:

  

Die indirekte Änderung des überladenen Elements von MyClass hat keine Auswirkung

Wo MyClass erweitert ArrayObject . Ich habe viel Code, der davon abhängt, verschachtelte Elemente wie diese zu entschärfen, also wie kann ich das zum Laufen bringen?

    
mpen 02.04.2012, 18:36
quelle

4 Antworten

11

Ein Weg, es zu tun

%Vor%

druckt:

%Vor%

Müsste etwas länger darüber nachdenken, warum die ursprünglich verwendete Syntax das Element nicht entfernt.

BEARBEITEN: Erklärung des Verhaltens

Was passiert, ist der Aufruf von unset($a['b']['c']); wird übersetzt in:

%Vor%

da $temp eine Kopie von $a anstelle einer Referenz darauf ist, verwendet PHP intern copy-on-write und erstellt ein zweites Array, in dem $temp nicht ['b']['c'] , sondern $a hat tut es immer noch.

ANDERE BEARBEITUNG: Wiederverwendbarer Code

Also, egal wie Sie es schneiden, scheint es, als ob Sie versuchen, function offsetGet($index) zu überladen, um function &offsetGet($index) zu sein, führt zu Ärger; Also hier ist die kürzeste Hilfsmethode, die ich als statische Methode oder Instanzmethode in einer Unterklasse von ArrayObject hinzugefügt habe, was auch immer dein Boot schwimmt:

%Vor%

Also würde der ursprüngliche Code

werden %Vor%

NOCH EINE ANDERE BEARBEITUNG: OO-Lösung

OK - Ich muss also heute morgen gekrochen sein. Ich habe einen Fehler in meinem Code gefunden, und wenn wir ihn überarbeitet haben, können wir eine Lösung implementieren, die auf OO basiert.

Nur damit Sie wissen, ich habe es versucht, Erweiterung segfaults ..:

%Vor%

Die Implementierung eines Dekorators funktioniert dagegen wie ein Zauber:

%Vor%

Nun funktioniert dieser Code wie gewünscht:

%Vor%

Muss noch etwas Code ändern. Ich sehe das nicht anders.

    
quickshiftin 02.04.2012, 18:48
quelle
4

Es scheint mir, dass der "überladene" Klammeroperator von ArrayObject eine Kopie des verschachtelten Arrays und keine Referenz auf das Original zurückgibt. Wenn Sie also $a['b'] aufrufen, erhalten Sie eine Kopie des internen Arrays, das ArrayObject zum Speichern der Daten verwendet. Wenn Sie es in $a['b']['c'] auflösen, erhalten Sie nur das Element "c" innerhalb einer Kopie. Wenn Sie also unset() aufrufen, wird das Element "c" im Original nicht deaktiviert.

ArrayObject implementiert die ArrayAccess -Schnittstelle , was tatsächlich die Klammer erlaubt Operator an einem Objekt arbeiten. Die Dokumentation für ArrayAccess::offsetGet gibt an, dass ab PHP 5.3.4 Verweise auf die Originaldaten im internen Array von ArrayObject mit dem Operator =& erfasst werden können, als in seinem Beispiel angegeben.

    
inspector-g 02.04.2012 19:06
quelle
1

Sie können unset($a->b['c']); anstelle von unset($a['b']['c']); für den Fall verwenden, dass es kein großes Problem gibt, eine solche Ersetzung für alle Situationen in Ihrem Projekt durchzuführen

    
Pavel Perminov 13.03.2014 21:33
quelle
0

Ich habe anscheinend eine Teillösung . unset scheint zu funktionieren, wenn alle verschachtelten Arrays Instanzen von ArrayObject sind. Um sicherzustellen, dass alle verschachtelten Arrays auch ArrayObjects sind, können wir stattdessen von dieser Klasse ableiten:

%Vor%

(aktualisiert für Rekursivität; ungetestet)

Und dann, wenn Sie versuchen, ein verschachteltes Array hinzuzufügen, wird es automatisch in ein ArrayWrapper konvertiert.

Leider funktionieren viele andere Array-Funktionen wie array_key_exists nicht mit ArrayObjects.

    
mpen 02.04.2012 23:09
quelle

Tags und Links