json_decode для пользовательского класса - PullRequest
71 голосов
/ 22 марта 2011

Возможно ли декодировать строку json в объект, отличный от stdClass?

Ответы [ 10 ]

84 голосов
/ 23 марта 2011

Не автоматически.Но вы можете сделать это по старинке.

$data = json_decode($json, true);

$class = new Whatever();
foreach ($data as $key => $value) $class->{$key} = $value;

Или, наоборот, вы можете сделать это более автоматическим:

class Whatever {
    public function set($data) {
        foreach ($data AS $key => $value) $this->{$key} = $value;
    }
}

$class = new Whatever();
$class->set($data);

Редактировать : стать немного изумительнее:

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);
24 голосов
/ 18 декабря 2013

Вы можете сделать это - это клудж, но вполне возможно. Мы должны были это делать, когда начали складывать вещи на диване.

$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 

В наших тестах это было намного быстрее, чем пытаться перебрать все переменные класса.

Предупреждение: не будет работать для вложенных объектов, отличных от stdClass

Изменить: имейте в виду источник данных, настоятельно рекомендуется, чтобы вы не делали этого с ненадежными данными от пользователей без тщательного анализа рисков.

21 голосов
/ 27 января 2014

Мы создали JsonMapper для автоматического сопоставления объектов JSON с нашими собственными модельными классами. Отлично работает с вложенными / дочерними объектами.

Для отображения он использует только информацию о типе докблока, которая в любом случае имеется в большинстве свойств класса:

<?php
$mapper = new JsonMapper();
$contactObject = $mapper->map(
    json_decode(file_get_contents('http://example.org/contact.json')),
    new Contact()
);
?>
11 голосов
/ 19 января 2015

Вы можете использовать библиотеку сериализатора J ohannes Schmitt .

$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json');

В последней версии сериализатора JMS синтаксис:

$serializer = SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, MyObject::class, 'json');
3 голосов
/ 24 августа 2016

Вы можете сделать обертку для своего объекта и сделать обертку похожей на сам объект. И это будет работать с многоуровневыми объектами.

<?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
3 голосов
/ 22 марта 2011

Нет, это невозможно с PHP 5.5.1.

Единственное, что возможно, это иметь json_decode возвращаемых ассоциированных массивов вместо объектов StdClass.

1 голос
/ 18 августа 2016

Вы можете сделать это следующим образом.

<?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;
            }
        }
    }
}

?>

Для более подробной информации посетите создавать пользовательские-класс-в-PHP-с-JSON или массива

0 голосов
/ 03 декабря 2015

Я однажды создал абстрактный базовый класс для этой цели. Давайте назовем это JsonConvertible. Он должен сериализовать и десериализовать публичных членов. Это возможно при использовании Reflection и поздней статической привязки.

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();

Просто по памяти, так что наверное не безупречно. Вам также придется исключить статические свойства и дать производным классам возможность игнорировать некоторые свойства при сериализации в / из json. Я надеюсь, что вы поняли, тем не менее.

0 голосов
/ 23 марта 2011

JSON - это простой протокол для передачи данных между различными языками программирования (и это также подмножество JavaScript), который поддерживает только определенные типы: числа, строки, массивы / списки, объекты / дикты. Объекты - это просто карты «ключ = значение», а массивы - упорядоченные списки.

Таким образом, нет никакого способа выразить пользовательские объекты универсальным способом. Решение заключается в определении структуры, в которой ваши программы будут знать, что это пользовательский объект.

Вот пример:

{ "cls": "MyClass", fields: { "a": 123, "foo": "bar" } }

Это можно использовать для создания экземпляра MyClass и установки полей a и foo на 123 и "bar".

0 голосов
/ 23 марта 2011

Как говорит Гордон, это невозможно. Но если вы ищете способ получить строку, которая может быть декодирована в качестве экземпляра класса Give, вы можете использовать serialize и десериализацию вместо этого.

class Foo
{

    protected $bar = 'Hello World';

    function getBar() {
        return $this->bar;
    }

}

$string = serialize(new Foo);

$foo = unserialize($string);
echo $foo->getBar();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...