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?
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:
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:
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.
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.
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
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:
(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.
Tags und Links php arrayobject