Der Titel mag ein bisschen albern erscheinen, aber ich meine das total ernst. Heute bei der Arbeit stieß ich auf ein seltsames PHP-Verhalten, das ich nicht erklären konnte. Glücklicherweise ist dieses Verhalten in PHP 7.4 behoben, so dass anscheinend auch jemand darauf gestoßen ist.
Ich habe ein kleines Beispiel gemacht, um zu veranschaulichen, was schief gelaufen ist:
<?php
class A {
private $a = 'This is $a from A';
public $b = 'This is $b from A';
public function __sleep(): array
{
var_dump(array_keys(get_object_vars($this)));
return [];
}
}
class B extends A
{
public $a = 'This is $a from B';
}
$b = new B;
serialize($b);
Führen Sie diesen Code hier aus: https://3v4l.org/DBt3o
Hier ist eine kleine Erklärung, was hier los ist. Wir müssen Klassen A und B, die beide eine Eigenschaft teilen $a
. Sorgfältige Leser bemerkten, dass die Immobilie $a
zwei verschiedene Sichtbarkeiten hat (öffentlich, privat). Bisher nichts Besonderes. Die Magie geschieht in der __sleep
Methode, die magisch aufgerufen wird, wenn wir serialize
unsere Instanz. Wir wollen alle Objektvariablen, die wir erhalten get_object_vars
, auf nur die Schlüssel mit reduzieren array_keys
und alles mit ausgeben var_dump
.
Ich würde so etwas erwarten (dies geschieht seit PHP 7.4 und ist meine erwartete Ausgabe):
array(2) {
[0]=>
string(1) "b"
[1]=>
string(1) "a"
}
Aber was ich bekomme ist folgendes:
array(3) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
string(1) "a"
}
Wie könnte es sein, dass PHP ein Array mit zwei völlig identischen Schlüsseln liefert? Wer kann erklären, was hier intern passiert, weil ich in einfachem PHP kein Array mit zwei völlig identischen Schlüsseln generieren kann? Oder vermisse ich hier etwas Offensichtliches?
Meine Mitarbeiter wollten mir zunächst nicht glauben, aber keiner von ihnen hatte eine gute Erklärung dafür, nachdem sie verstanden hatten, was hier passiert.
Ich würde wirklich gerne eine gute Erklärung sehen.
quelle
var_dump(array_keys((array)$this));
Antworten:
Ich konnte keinen Bericht für den Fehler in der Frage finden, aber interessanterweise scheint dieses Commit dasselbe zu behandeln:
Der Testcode ist gut geschrieben, mit einer einfachen Änderung könnten wir ihn hier haben:
Aufruf
var_dump()
zu$props
Shows:Zurück zu Ihrer Frage:
Ja, Sie können kein Array mit zwei identischen Schlüsseln haben:
Ergebnisse in:
Aber lassen Sie mich Ihnen nicht zustimmen,
two completely identical keys
da diese beiden Elemente mit identischen Schlüsselnamen nicht intern mit identischen Schlüsseln in einer Hashtabelle gespeichert sind. Das heißt, diese werden außer bei möglichen Kollisionen als eindeutige Ganzzahlen gespeichert, und da dies intern aufgetreten ist, wurde die Einschränkung der Benutzereingaben ignoriert.quelle
Nachdem Sie ein wenig damit herumgespielt haben, sieht es so aus, als ob dies nicht davon abhängt
__sleep()
.Anscheinend war dies in früheren Versionen von PHP 7 immer der Fall (aber anscheinend nicht in PHP 5). Dieses kleinere Beispiel zeigt das gleiche Verhalten.
Ausgabe von PHP 7.0 - 7.3
Ich denke, das Private
$a
im Elternteil ist eine andere Eigenschaft als das Öffentliche$a
im Kind. Wenn Sie die Sichtbarkeit in ändern, ändernB
Sie nicht die Sichtbarkeit des$a
InA
, sondern erstellen wirklich eine neue Eigenschaft mit demselben Namen. Wenn Sievar_dump
das Objekt selbst sind, können Sie beide Eigenschaften sehen.Es sollte jedoch keine großen Auswirkungen haben, da Sie nicht über die übergeordnete Klasse in der untergeordneten Klasse auf die private Eigenschaft zugreifen können, obwohl Sie sehen können, dass sie in diesen früheren PHP 7-Versionen vorhanden ist.
quelle
a
gibt auch den zweiten zurückThis is $a from A
.Mein paar Cent.
Ich weiß nichts über Mitarbeiter, aber ich habe nicht geglaubt und dachte, das sei ein Witz.
Zur Erklärung: Das Problem befindet sich definitiv unter der Variablen "get_object_vars", da es ein doppeltes assoziatives Array zurückgibt. Sollte zwei verschiedene Hash-Tabellenwerte für denselben Schlüssel sein (was nicht möglich ist, aber die einzige Erklärung kommt). Ich konnte keine Links zur internen Implementierung von get_object_vars () finden (obwohl PHP auf Open Source basiert, so dass es möglich ist, Code abzurufen und irgendwie zu debuggen). Außerdem denke ich (bisher erfolglos) darüber nach, wie ich die Array-Darstellung im Speicher einschließlich der Hash-Tabelle sehen kann. Auf der anderen Seite konnte ich PHP "legale" Funktionen verwenden und einige Tricks mit Array machen.
Dies ist mein Versuch, einige Funktionen mit diesem assoziativen Array zu testen. Unten ist die Ausgabe. Keine Erklärung erforderlich - Sie können alles sehen und den gleichen Code selbst ausprobieren, also nur einige Kommentare.
Meine Umgebung ist PHP 7.2.12 x86 (32 Bit) - na ja ... schade um mich
Ich werde "Magie" und Serialisierung los und habe nur Dinge übrig gelassen, die Probleme verursachen.
Einige Umgestaltungen der Klassen A und B sowie des Funktionsaufrufs wurden abgeschlossen.
Der $ Schlüssel unter Klasse A muss privat sein, sonst kein Wunder.
Teiletests vars - nichts Interessantes außer dem Hauptproblem.
Teiletest copy_vars - Array wurde mit Duplikat kopiert !! Neuer Schlüssel wurde erfolgreich hinzugefügt.
Teiletestiteration und new_vars - Die Iteration wurde problemlos dupliziert, aber das neue Array akzeptierte kein Duplikat, der letzte Schlüssel wurde akzeptiert.
Testersatz - Austausch beim zweiten Schlüssel abgeschlossen, doppelter Aufenthalt.
Das Testen von ksort - array hat sich nicht geändert, Duplikate wurden nicht erkannt
Testen von asort - Nachdem ich Werte geändert und asort ausgeführt hatte, konnte ich die Reihenfolge ändern und doppelte Schlüssel austauschen. Jetzt wird der erste Schlüssel zum zweiten und der neue Schlüssel ist derjenige, wenn wir Array für Schlüssel aufrufen oder einen Schlüssel zuweisen. Infolgedessen konnte ich beide Schlüssel ändern !! Bevor ich dachte, dass ein doppelter Schlüssel unsichtbar ist, ist jetzt klar, dass der letzte Schlüssel funktioniert, wenn wir auf den Schlüssel verweisen oder ihn zuweisen.
Konvertierung in ein stdClass-Objekt - auf keinen Fall! Nur letzter Schlüssel akzeptiert!
Testen auf Unset - gute Arbeit! Letzter Schlüssel entfernt, aber der erste Schlüssel ist verantwortlich und der einzige Schlüssel übrig, keine Duplikate.
Interner Repräsentationstest - Dies ist ein Thema, um einige andere Funktionen hinzuzufügen und die Quelle der Duplizierung zu ermitteln. Ich denke jetzt darüber nach.
Die Ergebnisausgabe befindet sich unterhalb des Codes.
Jetzt ausgeben:
quelle