Ist es möglich, einen JSON-String in ein anderes Objekt als stdClass zu dekodieren?
Ist es möglich, einen JSON-String in ein anderes Objekt als stdClass zu dekodieren?
Antworten:
Nicht automatisch. Aber Sie können es auf der altmodischen Route tun.
$data = json_decode($json, true);
$class = new Whatever();
foreach ($data as $key => $value) $class->{$key} = $value;
Alternativ können Sie dies auch automatischer gestalten:
class Whatever {
public function set($data) {
foreach ($data AS $key => $value) $this->{$key} = $value;
}
}
$class = new Whatever();
$class->set($data);
Edit : etwas schicker werden:
class JSONObject {
public function __construct($json = false) {
if ($json) $this->set(json_decode($json, true));
}
public function set($data) {
foreach ($data AS $key => $value) {
if (is_array($value)) {
$sub = new JSONObject;
$sub->set($value);
$value = $sub;
}
$this->{$key} = $value;
}
}
}
// These next steps aren't necessary. I'm just prepping test data.
$data = array(
"this" => "that",
"what" => "who",
"how" => "dy",
"multi" => array(
"more" => "stuff"
)
);
$jsonString = json_encode($data);
// Here's the sweetness.
$class = new JSONObject($jsonString);
print_r($class);
Wir haben JsonMapper erstellt , um JSON-Objekte automatisch unseren eigenen Modellklassen zuzuordnen . Es funktioniert gut mit verschachtelten / untergeordneten Objekten.
Für die Zuordnung werden nur Informationen zum Docblock-Typ verwendet, die die meisten Klasseneigenschaften ohnehin haben:
<?php
$mapper = new JsonMapper();
$contactObject = $mapper->map(
json_decode(file_get_contents('http://example.org/contact.json')),
new Contact()
);
?>
Sie können es tun - es ist ein Kludge, aber absolut möglich. Wir mussten tun, als wir anfingen, Dinge auf der Couchbase zu lagern.
$stdobj = json_decode($json_encoded_myClassInstance); //JSON to stdClass
$temp = serialize($stdobj); //stdClass to serialized
// Now we reach in and change the class of the serialized object
$temp = preg_replace('@^O:8:"stdClass":@','O:7:"MyClass":',$temp);
// Unserialize and walk away like nothing happend
$myClassInstance = unserialize($temp); // Presto a php Class
In unseren Benchmarks war dies viel schneller als der Versuch, alle Klassenvariablen zu durchlaufen.
Vorsichtsmaßnahme: Funktioniert nicht für andere verschachtelte Objekte als stdClass
Bearbeiten: Beachten Sie die Datenquelle. Es wird dringend empfohlen, dies nicht mit nicht vertrauenswürdigen Daten von Benutzern zu tun, ohne die Risiken sehr sorgfältig zu analysieren.
{ "a": {"b":"c"} }
, wo das Objekt in a
einer anderen Klasse ist und nicht nur ein assoziatives Array?
Sie können die Serializer-Bibliothek von J ohannes Schmitt verwenden .
$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json');
In der neuesten Version des JMS-Serializers lautet die Syntax:
$serializer = SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, MyObject::class, 'json');
::class
Notation verwenden: php.net/manual/en/…
Sie können einen Wrapper für Ihr Objekt erstellen und den Wrapper so aussehen lassen, als wäre er das Objekt selbst. Und es funktioniert mit mehrstufigen Objekten.
<?php
class Obj
{
public $slave;
public function __get($key) {
return property_exists ( $this->slave , $key ) ? $this->slave->{$key} : null;
}
public function __construct(stdClass $slave)
{
$this->slave = $slave;
}
}
$std = json_decode('{"s3":{"s2":{"s1":777}}}');
$o = new Obj($std);
echo $o->s3->s2->s1; // you will have 777
Nein, dies ist ab PHP 5.5.1 nicht möglich.
Das einzige, was möglich ist, ist, json_decode
assoziierte Arrays anstelle der StdClass-Objekte zurückzugeben.
Sie können es auf folgende Weise tun ..
<?php
class CatalogProduct
{
public $product_id;
public $sku;
public $name;
public $set;
public $type;
public $category_ids;
public $website_ids;
function __construct(array $data)
{
foreach($data as $key => $val)
{
if(property_exists(__CLASS__,$key))
{
$this->$key = $val;
}
}
}
}
?>
Weitere Informationen finden Sie unter create-custom-class-in-php-from-json-or-array
Wie Gordon sagt, ist das nicht möglich. Wenn Sie jedoch nach einer Möglichkeit suchen, eine Zeichenfolge zu erhalten, die als Instanz einer give-Klasse dekodiert werden kann, können Sie stattdessen serialize und unserialize verwenden.
class Foo
{
protected $bar = 'Hello World';
function getBar() {
return $this->bar;
}
}
$string = serialize(new Foo);
$foo = unserialize($string);
echo $foo->getBar();
Zu diesem Zweck habe ich einmal eine abstrakte Basisklasse erstellt. Nennen wir es JsonConvertible. Es sollte die öffentlichen Mitglieder serialisieren und deserialisieren. Dies ist durch Reflexion und späte statische Bindung möglich.
abstract class JsonConvertible {
static function fromJson($json) {
$result = new static();
$objJson = json_decode($json);
$class = new \ReflectionClass($result);
$publicProps = $class->getProperties(\ReflectionProperty::IS_PUBLIC);
foreach ($publicProps as $prop) {
$propName = $prop->name;
if (isset($objJson->$propName) {
$prop->setValue($result, $objJson->$propName);
}
else {
$prop->setValue($result, null);
}
}
return $result;
}
function toJson() {
return json_encode($this);
}
}
class MyClass extends JsonConvertible {
public $name;
public $whatever;
}
$mine = MyClass::fromJson('{"name": "My Name", "whatever": "Whatever"}');
echo $mine->toJson();
Nur aus dem Gedächtnis, also wahrscheinlich nicht fehlerfrei. Sie müssen auch statische Eigenschaften ausschließen und können abgeleiteten Klassen die Möglichkeit geben, einige Eigenschaften bei der Serialisierung zu / von json zu ignorieren. Ich hoffe, Sie haben trotzdem die Idee.
Verwenden Reflexion :
function json_decode_object(string $json, string $class)
{
$reflection = new ReflectionClass($class);
$instance = $reflection->newInstanceWithoutConstructor();
$json = json_decode($json, true);
$properties = $reflection->getProperties();
foreach ($properties as $key => $property) {
$property->setAccessible(true);
$property->setValue($instance, $json[$property->getName()]);
}
return $instance;
}
JSON ist ein einfaches Protokoll zum Übertragen von Daten zwischen verschiedenen Programmiersprachen (und es ist auch eine Teilmenge von JavaScript), das nur bestimmte Typen unterstützt: Zahlen, Zeichenfolgen, Arrays / Listen, Objekte / Dikte. Objekte sind nur Schlüssel = Wert-Maps und Arrays sind geordnete Listen.
Es gibt also keine Möglichkeit, benutzerdefinierte Objekte generisch auszudrücken. Die Lösung besteht darin, eine Struktur zu definieren, in der Ihre Programme wissen, dass es sich um ein benutzerdefiniertes Objekt handelt.
Hier ist ein Beispiel:
{ "cls": "MyClass", fields: { "a": 123, "foo": "bar" } }
Dies könnte verwendet werden, um eine Instanz von zu erstellen MyClass
und die Felder a
und foo
auf 123
und zu setzen "bar"
.
Ich ging voran und implementierte John Petits Antwort als Funktion ( Kern ):
function json_decode_to(string $json, string $class = stdClass::class, int $depth = 512, int $options = 0)
{
$stdObj = json_decode($json, false, $depth, $options);
if ($class === stdClass::class) return $stdObj;
$count = strlen($class);
$temp = serialize($stdObj);
$temp = preg_replace("@^O:8:\"stdClass\":@", "O:$count:\"$class\":", $temp);
return unserialize($temp);
}
Dies funktionierte perfekt für meinen Anwendungsfall. Die Antwort von Jewgenij Afanasjew erscheint mir jedoch ebenso vielversprechend. Es könnte möglich sein, dass Ihre Klasse einen zusätzlichen "Konstruktor" hat, wie folgt:
public static function withJson(string $json) {
$instance = new static();
// Do your thing
return $instance;
}
Dies ist auch von dieser Antwort inspiriert .
Ich bin überrascht, dass dies noch niemand erwähnt hat.
Verwenden Sie die Symfony Serializer-Komponente: https://symfony.com/doc/current/components/serializer.html
Serialisierung von Objekt zu JSON:
use App\Model\Person;
$person = new Person();
$person->setName('foo');
$person->setAge(99);
$person->setSportsperson(false);
$jsonContent = $serializer->serialize($person, 'json');
// $jsonContent contains {"name":"foo","age":99,"sportsperson":false,"createdAt":null}
echo $jsonContent; // or return it in a Response
Deserialisierung von JSON zu Object: (In diesem Beispiel wird XML verwendet, um die Flexibilität von Formaten zu demonstrieren.)
use App\Model\Person;
$data = <<<EOF
<person>
<name>foo</name>
<age>99</age>
<sportsperson>false</sportsperson>
</person>
EOF;
$person = $serializer->deserialize($data, Person::class, 'xml');