json_decode到自定义类

时间:2011-03-22 20:59:07

标签: php json

是否可以将json字符串解码为stdClass以外的对象?

14 个答案:

答案 0 :(得分:83)

不自动。但你可以用老式的路线来做。

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

答案 1 :(得分:24)

你可以做到 - 它是一个完全可能的kludge。当我们开始在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 

在我们的基准测试中,这比尝试迭代所有类变量要快得多。

警告:除了stdClass

之外,还不适用于嵌套对象

编辑:请记住数据来源,强烈建议您不要使用来自用户的不受信任的数据,而不要对这些风险进行非常谨慎的分析。

答案 2 :(得分:20)

我们构建了JsonMapper来自动将JSON对象映射到我们自己的模型类。它适用于嵌套/子对象。

它只依赖docblock类型信息进行映射,而大多数类属性都是这样:

<?php
$mapper = new JsonMapper();
$contactObject = $mapper->map(
    json_decode(file_get_contents('http://example.org/contact.json')),
    new Contact()
);
?>

答案 3 :(得分:11)

您可以使用J ohannes Schmitt's Serializer library

$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');

答案 4 :(得分:3)

不,从PHP 5.5.1开始就不可能。

唯一可能的是让json_decode返回关联数组而不是StdClass对象。

答案 5 :(得分:3)

您可以为对象创建一个包装器,并使包装器看起来像是对象本身。它将适用于多级对象。

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

答案 6 :(得分:3)

令我惊讶的是,现在还没有人提到。

使用Symfony序列化器组件:https://symfony.com/doc/current/components/serializer.html

从对象序列化为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

从JSON反序列化为对象(此示例使用XML只是为了演示格式的灵活性)

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

答案 7 :(得分:2)

使用Reflection

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

答案 8 :(得分:1)

你可以用以下方式来做..

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

&GT;

有关详细信息,请访问 create-custom-class-in-php-from-json-or-array

答案 9 :(得分:0)

戈登说不可能。但是,如果您正在寻找一种方法来获取可以作为给定类的实例进行解码的字符串,则可以使用serialize并反而取消序列化。

class Foo
{

    protected $bar = 'Hello World';

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

}

$string = serialize(new Foo);

$foo = unserialize($string);
echo $foo->getBar();

答案 10 :(得分:0)

我认为最简单的方法是:

function mapJSON($json, $class){
$decoded_object = json_decode($json);
   foreach ($decoded_object as $key => $value) {
            $class->$key = $value;
   }
   return $class;}

答案 11 :(得分:0)

我继续将John Petit's answer实现为函数(gist):

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

这对于我的用例来说非常理想。但是Yevgeniy Afanasyev's response对我来说同样有希望。可能会使您的班级有一个额外的“构造函数”,如下所示:

public static function withJson(string $json) {
    $instance = new static();
    // Do your thing
    return $instance;
}

这也受到this answer的启发。

答案 12 :(得分:0)

这里的所有内容都启发了我使用通用函数:

function loadJSON($Obj, $json)
{
     $dcod = json_decode($json);
     $prop = get_object_vars ( $dcod );
     foreach($prop as $key => $lock)
     {
        if(property_exists ( $Obj ,  $key ))
        {
            if(is_object($dcod->$key))
            {
                loadJSON($Obj->$key, json_encode($dcod->$key));
            }
            else
            {
                $Obj->$key = $dcod->$key;
            }
        }
    }
}

在类声明中调用:

class Bar{public $bar = " Boss";}
class Bas
{
    public $ber ;
    public $bas=" Boven"; 
    public function __construct() 
        {$this->ber = new Bar;}
}
class Baz
{
    public $bes ;
    public $baz=" Baaz";  
    public function __construct() 
        {$this->bes = new Bas;}
}

$Bazjson = '{"bes":{"ber":{"bar":"Baas"}}}';

$Bazobj = new Baz;

loadJSON($Bazobj, $Bazjson);
var_dump($Bazobj);

答案 13 :(得分:-1)

JSON是一种在各种编程语言之间传输数据的简单协议(它也是JavaScript的一个子集),它只支持某些类型:数字,字符串,数组/列表,对象/ dicts。对象只是键=值映射,而数组是有序列表。

因此无法以通用方式表达自定义对象。解决方案是定义一个结构,您的程序将知道它是一个自定义对象。

以下是一个例子:

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

这可用于创建MyClass的实例,并将字段afoo设置为123"bar"