Lösen typischer Probleme mit json_encode (PHP)

Dies ist ein kurzer Artikel über die wahrscheinlichsten Probleme mit json_encode und deren Lösungen. Manchmal, wenn wir Daten in json mit json_encode in php verschlüsseln , erhalten wir das falsche Ergebnis, das wir erwarten. Ich habe die drei häufigsten Probleme hervorgehoben, mit denen Programmierer konfrontiert sind:


  • Zugang zu Feldern
  • Textwertcodierung
  • numerische Werte

Zugriff auf Felder


Das Problem ist, dass json_encode nur auf die öffentlichen Felder des Objekts zugreifen kann. Zum Beispiel, wenn Sie eine Klasse haben


class Example { public $publicProperty; protected $protectedProperty; private $privateProperty; public function __construct($public, $protected, $private) { $this->publicProperty = $public; $this->protectedProperty = $protected; $this->privateProperty = $private; } } 

dann ist das Ergebnis des folgenden Codes:


 $obj = new Example("some", "value", "here"); echo json_encode($obj); // {"publicProperty":"some"} 

Wie Sie sehen, wurden nur öffentliche Felder in den resultierenden JSON aufgenommen.
Was tun, wenn Sie alle Felder benötigen?


Lösung


Für PHP <5.4:
Wir müssen eine Methode in der Klasse implementieren, die den fertigen JSON zurückgibt. Weil Innerhalb der Klasse gibt es Zugriff auf alle Felder, Sie können die korrekte Darstellung des Objekts für json_encode bilden


 class Example { public $publicProperty; protected $protectedProperty; private $privateProperty; public function __construct($public, $protected, $private) { $this->publicProperty = $public; $this->protectedProperty = $protected; $this->privateProperty = $private; } public function toJson() { return json_encode([ 'publicProperty' => $this->publicProperty, 'protectedProperty' => $this->protectedProperty, 'privateProperty' => $this->privateProperty, ]); } } 

Um json-a von einem Objekt zu erhalten, müssen Sie jetzt die toJson- Methode verwenden, anstatt json_encode direkt auf das Objekt anzuwenden


 $obj = new Example("some", "value", "here"); echo $obj->toJson(); 

Für php> = 5.4:
Es wird ausreichen, die JsonSerializable- Schnittstelle für unsere Klasse zu implementieren. Dazu muss eine jsonSerialize- Methode hinzugefügt werden, die eine Struktur zurückgibt , die das Objekt für json_encode darstellt


 class Example implements JsonSerializable { public $publicProperty; protected $protectedProperty; private $privateProperty; public function __construct($public, $protected, $private) { $this->publicProperty = $public; $this->protectedProperty = $protected; $this->privateProperty = $private; } public function jsonSerialize() { return [ 'publicProperty' => $this->publicProperty, 'protectedProperty' => $this->protectedProperty, 'privateProperty' => $this->privateProperty, ]; } } 

Jetzt können wir json_encode wie bisher verwenden


 $obj = new Example("some", "value", "here"); echo json_encode($obj); // {"publicProperty":"some","protectedProperty":"value","privateProperty":"here"} 

Warum nicht den Ansatz mit der toJson-Methode verwenden?


Viele haben wahrscheinlich bemerkt, dass der Ansatz zum Erstellen einer Methode, die json zurückgibt, in Versionen von php> = 5.4 verwendet werden kann. Warum also nicht davon profitieren? Die Sache ist, dass Ihre Klasse als Teil einer anderen Datenstruktur verwendet werden kann.


 echo json_encode([ 'status' => true, 'message' => 'some message', 'data' => new Example("some", "value", "here"), ]); 

und das ergebnis wird schon ganz anders sein.
Die Klasse kann auch von anderen Programmierern verwendet werden, für die diese Art des Abrufens von JSON von einem Objekt möglicherweise nicht ganz offensichtlich ist.



Was ist, wenn ich viele Felder im Unterricht habe?


In diesem Fall können Sie die Funktion get_object_vars verwenden


 class Example implements JsonSerializable { public $publicProperty; protected $protectedProperty; private $privateProperty; protected $someProp1; ... protected $someProp100500; public function __construct($public, $protected, $private) { $this->publicProperty = $public; $this->protectedProperty = $protected; $this->privateProperty = $private; } public function jsonSerialize() { $fields = get_object_vars($this); // -  ... return $fields; } } 

Und wenn Sie private Felder aus einer Klasse benötigen, die nicht bearbeitet werden können?


Es kann vorkommen, dass Sie private Felder in json abrufen müssen ( private , da der Zugriff auf geschützte Felder durch Vererbung möglich ist). In diesem Fall muss Reflektion verwendet werden:


 class Example { public $publicProperty = "someValue"; protected $protectedProperty; private $privateProperty1; private $privateProperty2; private $privateProperty3; public function __construct($privateProperty1, $privateProperty2, $privateProperty3, $protectedProperty) { $this->protectedProperty = $protectedProperty; $this->privateProperty1 = $privateProperty1; $this->privateProperty2 = $privateProperty2; $this->privateProperty3 = $privateProperty3; } } $obj = new Example("value1", 12, "21E021", false); $reflection = new ReflectionClass($obj); $public = []; foreach ($reflection->getProperties() as $property) { $property->setAccessible(true); $public[$property->getName()] = $property->getValue($obj); } echo json_encode($public); //{"publicProperty":"someValue","protectedProperty":false,"privateProperty1":"value1","privateProperty2":12,"privateProperty3":"21E021"} 

Codierung von Textwerten


Kyrillische und andere Zeichen in UTF8


Die zweite Art von häufigem json_encode- Problem sind Codierungsprobleme. Häufig enthalten Textwerte, die in json codiert werden müssen, Zeichen in UTF8 (einschließlich Kyrillisch). Daher werden diese Zeichen in Form von Codes dargestellt:


 echo json_encode(" or ₳ ƒ 元 ﷼ ₨ ௹ ¥ ₴ £ ฿ $"); // "\u043a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u0430 or \u20b3 \u0192 \u5143 \ufdfc \u20a8 \u0bf9 \uffe5 \u20b4 \uffe1 \u0e3f \uff04" 

Die Anzeige solcher Zeichen wird sehr einfach behandelt - indem das JSON_UNESCAPED_UNICODE- Flag als zweites Argument zur json_encode- Funktion hinzugefügt wird:


 echo json_encode(" or ₳ ƒ 元 ﷼ ₨ ௹ ¥ ₴ £ ฿ $", JSON_UNESCAPED_UNICODE); // " or ₳ ƒ 元 ﷼ ₨ ௹ ¥ ₴ £ ฿ $" 

Symbole in anderen Kodierungen


Die Funktion json_encode behandelt Zeichenfolgenwerte als Zeichenfolgen in UTF8, was bei abweichender Codierung zu Fehlern führen kann. Betrachten Sie ein kleines Stück Code (dieses Codebeispiel ist so einfach wie möglich, um eine Problemsituation zu veranschaulichen).


 echo json_encode(["p" => $_GET['p']]); 

Auf den ersten Blick deutet nichts auf Probleme hin, und was kann hier schief gehen? Das habe ich auch gedacht. In den allermeisten Fällen wird alles funktionieren, und aus diesem Grund habe ich etwas länger gebraucht, als ich das erste Mal auf das Ergebnis von json_encode gestoßen bin, das falsch war.


Angenommen, p = % EF% F2% E8% F6% E0 (Beispiel: localhost? =% EF% F2% E8% F6% E0 ), um diese Situation wiederherzustellen.
* Variablen in superglobalen Arrays $ _GET und $ _REQUEST sind bereits dekodiert.


 $decoded = urldecode("%EF%F2%E8%F6%E0"); var_dump(json_encode($decoded)); // bool(false) var_dump(json_last_error_msg()); // string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" 

Wie Sie aus dem Fehler ersehen können: Das Problem mit der Codierung des übertragenen Strings (das ist nicht UTF8). Die Lösung des Problems liegt auf der Hand - bringen Sie den Wert auf UTF8


 $decoded = urldecode("%EF%F2%E8%F6%E0"); $utf8 = utf8_encode($decoded); echo json_encode($utf8); // "ïòèöà" 

Zahlenwerte


Der letzte typische Fehler bezieht sich auf die Codierung numerischer Werte.


Zum Beispiel:


 echo json_encode(["string_float" => "3.0"]); // {"string_float":"3.0"} 

Wie Sie wissen, ist PHP keine streng typisierte Sprache und erlaubt es Ihnen, Zahlen als Zeichenkette zu verwenden. In den meisten Fällen führt dies nicht zu Fehlern in der PHP-Anwendung. Da json jedoch häufig zum Übertragen von Nachrichten zwischen Anwendungen verwendet wird, kann dieses Format zum Schreiben von Zahlen in einer anderen Anwendung Probleme verursachen. Es wird empfohlen, das JSON_NUMERIC_CHECK- Flag zu verwenden:


 echo json_encode(["string_float" => "3.0"], JSON_NUMERIC_CHECK); // {"string_float":3} 

Schon besser. Wie Sie jedoch sehen können, wurde aus "3.0" "3", was in den meisten Fällen als "int" interpretiert wird. Wir verwenden ein weiteres Flag JSON_PRESERVE_ZERO_FRACTION für die korrekte Konvertierung in float:


 echo json_encode(["string_float" => "3.0"], JSON_NUMERIC_CHECK | JSON_PRESERVE_ZERO_FRACTION); // {"string_float":3.0} 

Ich bitte Sie außerdem, auf das folgende Codefragment zu achten, das eine Reihe möglicher Probleme mit json_encode und numerischen Werten veranschaulicht :


 $data = [ "0000021", //   6.12345678910111213, //     ( ) "+81011321515", //  "21E021", //   ]; echo json_encode($data, JSON_NUMERIC_CHECK); //[ // 21, // 6.1234567891011, // 81011321515, // 2.1e+22 // ] 

Danke fürs Lesen.


Ich freue mich, in den Kommentaren eine Beschreibung der Probleme zu sehen, auf die Sie gestoßen sind und die im Artikel nicht erwähnt wurden

Source: https://habr.com/ru/post/de483492/


All Articles