È possibile decodificare una stringa json in un oggetto diverso da stdClass?
È possibile decodificare una stringa json in un oggetto diverso da stdClass?
Risposte:
Non automaticamente. Ma puoi farlo alla vecchia maniera.
$data = json_decode($json, true);
$class = new Whatever();
foreach ($data as $key => $value) $class->{$key} = $value;
O in alternativa, potresti renderlo più automatico:
class Whatever {
public function set($data) {
foreach ($data AS $key => $value) $this->{$key} = $value;
}
}
$class = new Whatever();
$class->set($data);
Modifica : diventare un po 'più elaborato:
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);
Abbiamo costruito JsonMapper per mappare automaticamente gli oggetti JSON sulle nostre classi modello. Funziona bene con oggetti nidificati / figli.
Si basa solo sulle informazioni sul tipo di docblock per la mappatura, che la maggior parte delle proprietà di classe hanno comunque:
<?php
$mapper = new JsonMapper();
$contactObject = $mapper->map(
json_decode(file_get_contents('http://example.org/contact.json')),
new Contact()
);
?>
Puoi farlo - è un kludge ma totalmente possibile. Dovevamo farlo quando abbiamo iniziato a memorizzare le cose in couchbase.
$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
Nei nostri benchmark questo è stato molto più veloce rispetto al tentativo di iterare tutte le variabili di classe.
Avvertenza: non funzionerà per oggetti nidificati diversi da stdClass
Modifica: tieni presente l'origine dei dati, si consiglia vivamente di non farlo con dati non attendibili degli utenti senza un'analisi molto attenta dei rischi.
{ "a": {"b":"c"} }
, dove l'oggetto a
è di un'altra classe e non solo un array associativo?
Potresti usare la libreria Serializer di J ohannes Schmitt .
$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json');
Nell'ultima versione del serializzatore JMS la sintassi è:
$serializer = SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, MyObject::class, 'json');
::class
la notazione: php.net/manual/en/...
Puoi creare un involucro per il tuo oggetto e fare in modo che l'involucro sembri l'oggetto stesso. E funzionerà con oggetti multilivello.
<?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
No, questo non è possibile a partire da PHP 5.5.1.
L'unica cosa possibile è avere json_decode
matrici associate di ritorno invece degli oggetti StdClass.
Puoi farlo nel modo seguente ..
<?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;
}
}
}
}
?>
Per maggiori dettagli visita create-custom-class-in-php-from-json-or-array
Sono sorpreso che nessuno ne abbia parlato ancora.
Usa il componente Serializer di Symfony: https://symfony.com/doc/current/components/serializer.html
Serializzazione da Object a 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
Deserializzazione da JSON a Object: (questo esempio utilizza XML solo per dimostrare la flessibilità dei formati)
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');
Usa la riflessione :
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;
}
Come dice Gordon non è possibile. Ma se stai cercando un modo per ottenere una stringa che possa essere decodificata come istanza di una classe give, puoi invece usare serialize e unserialize.
class Foo
{
protected $bar = 'Hello World';
function getBar() {
return $this->bar;
}
}
$string = serialize(new Foo);
$foo = unserialize($string);
echo $foo->getBar();
Una volta ho creato una classe base astratta per questo scopo. Chiamiamolo JsonConvertible. Dovrebbe serializzare e deserializzare i membri pubblici. Ciò è possibile utilizzando la riflessione e l'associazione statica tardiva.
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();
Solo dalla memoria, quindi probabilmente non impeccabile. Dovrai anche escludere proprietà statiche e potresti dare alle classi derivate la possibilità di ignorare alcune proprietà quando serializzate da / a json. Spero che tu abbia comunque l'idea.
JSON è un semplice protocollo per trasferire dati tra vari linguaggi di programmazione (ed è anche un sottoinsieme di JavaScript) che supporta solo alcuni tipi: numeri, stringhe, array / elenchi, oggetti / dict. Gli oggetti sono solo key = value map e gli array sono elenchi ordinati.
Quindi non c'è modo di esprimere oggetti personalizzati in modo generico. La soluzione è definire una struttura in cui i tuoi programmi sapranno che si tratta di un oggetto personalizzato.
Ecco un esempio:
{ "cls": "MyClass", fields: { "a": 123, "foo": "bar" } }
Questo potrebbe essere utilizzato per creare un'istanza di MyClass
e impostare i campi a
e foo
su 123
e "bar"
.
Sono andato avanti e ho implementato la risposta di John Petit , in funzione ( sintesi ):
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);
}
Ha funzionato perfettamente per il mio caso d'uso. Tuttavia la risposta di Yevgeniy Afanasyev mi sembra altrettanto promettente. Potrebbe essere possibile che la tua classe abbia un "costruttore" extra, in questo modo:
public static function withJson(string $json) {
$instance = new static();
// Do your thing
return $instance;
}
Anche questo è ispirato da questa risposta .