json_decode कस्टम वर्ग के लिए


87

क्या stdClass के अलावा किसी ऑब्जेक्ट के लिए json स्ट्रिंग को डिकोड करना संभव है?


3
इतने सालों के बाद इस पर कुछ भी नया नहीं है?
विक्टर

मुझे एक समाधान मिला जो मेरे लिए काम करता है stackoverflow.com/a/48838378/8138241
जेसन लियू

जवाबों:


96

अपने आप नहीं। लेकिन आप इसे पुराने जमाने का मार्ग मान सकते हैं।

$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
मैं आपको सुझाव देता हूं, केवल यह टिप्पणी करने के लिए कि यह नेस्टेड ऑब्जेक्ट्स (STDClass या परिवर्तित ऑब्जेक्ट के अलावा) के साथ काम नहीं करेगा
javier_domenech

34

हमने JsonMapper का निर्माण किया को JSON ऑब्जेक्ट्स को अपने मॉडल कक्षाओं में स्वचालित रूप से मैप करने के लिए । यह नेस्टेड / चाइल्ड ऑब्जेक्ट्स के साथ ठीक काम करता है।

यह केवल मानचित्रण के लिए डॉकब्लॉक प्रकार की जानकारी पर निर्भर करता है, जो कि अधिकांश वर्ग गुणों का वैसे भी है:

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

1
वाह! यह सिर्फ आश्चर्यजनक है।
वोटशाइन

आप OSL3 लाइसेंस की व्याख्या कर सकते हैं? यदि मैं किसी वेबसाइट पर JsonMapper का उपयोग करता हूं, तो क्या मुझे उस वेबसाइट का स्रोत कोड जारी करना चाहिए? अगर मैं किसी डिवाइस को बेचने वाले कोड में JsonMapper का उपयोग करता हूं, तो क्या उस डिवाइस के सभी कोड ओपन सोर्स होने चाहिए?
एरिका

नहीं, आपको केवल उन परिवर्तनों को प्रकाशित करना होगा जो आप JsonMapper को करते हैं।
cweiske

29

आप इसे कर सकते हैं - यह एक कीचड़ है लेकिन पूरी तरह से संभव है। हमें तब करना पड़ा जब हमने काउचबेस में चीजों को स्टोर करना शुरू किया।

$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 के अलावा नेस्टेड ऑब्जेक्ट्स के लिए काम नहीं करेगा

संपादित करें: डेटा स्रोत को ध्यान में रखें, यह दृढ़ता से अनुशंसा की जाती है कि आप जोखिमों के बहुत ही कुशल विश्लेषण के बिना उपयोगकर्ताओं से यह अविश्वसनीय डेटा प्रदान नहीं करते हैं।


1
क्या यह काम अतिक्रमित उपवर्गों के साथ करता है। उदाहरण के लिए { "a": {"b":"c"} }, जहां वस्तु aएक अन्य वर्ग की है और न केवल एक सहयोगी सरणी है?
जे-राऊ

2
नहीं, json_decode उप-ऑब्जेक्ट्स सहित stdclass ऑब्जेक्ट बनाता है, यदि आप चाहते हैं कि उन्हें कुछ और हो तो आपको प्रत्येक ऑब्जेक्ट को ऊपर के रूप में शामिल करना होगा।
जॉन पेटिट

धन्यवाद, यही मैंने कल्पना की थी
जे-राऊ

कैसे इस समाधान के बारे में वस्तुओं पर जहां निर्माता के पैरामीटर हैं। मैं इसे काम नहीं कर सकता। मैं उम्मीद कर रहा था कि कोई मुझे इस दिशा में काम करने के लिए सही दिशा में इशारा कर सकता है, जो किसी पैरामीटर के साथ एक कस्टम कंस्ट्रक्टर है।
मार्को

मैंने आगे बढ़कर इसे एक समारोह में बनाया। ध्यान दें कि यह अभी भी उपवर्गों के साथ काम नहीं करता है। gist.github.com/sixpeteunder/2bec86208775f131ce686d42f18d8621
पीटर लेनजो

16

आप J ohannes Schmitt के Serializer लाइब्रेरी का उपयोग कर सकते हैं ।

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

जेएमएस धारावाहिक के नवीनतम संस्करण में वाक्य रचना है:

$serializer = SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, MyObject::class, 'json');

2
सिंटैक्स JMS Serializer संस्करण पर निर्भर नहीं है, बल्कि PHP संस्करण पर - PHP5.5 से शुरू होकर आप ::classसंकेतन का उपयोग कर सकते हैं : php.net/manual/en/…
Ivan Yarych

4

आप अपनी वस्तु के लिए एक आवरण बना सकते हैं और आवरण को ऐसा बना सकते हैं जैसे वह वस्तु है। और यह बहुस्तरीय वस्तुओं के साथ काम करेगा।

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

नहीं, यह PHP 5.5.1 के रूप में संभव नहीं है।

json_decodeStdClass ऑब्जेक्ट्स के बजाय वापसी सहयोगी सरणियों के लिए केवल एक ही चीज़ संभव है ।


3

आप इसे नीचे तरीके से कर सकते हैं।

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

?>

अधिक जानकारी के लिए create-custom-in-php-from-json-or-array देखें


3

मुझे आश्चर्य है कि किसी ने भी इसका उल्लेख नहीं किया, फिर भी।

Symfony Serializer घटक का उपयोग करें: https://symfony.com/doc/current/compords/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 से ऑब्जेक्ट के लिए Deserializing: (यह उदाहरण केवल स्वरूपों के लचीलेपन को प्रदर्शित करने के लिए 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');

2

प्रतिबिंब का उपयोग करें :

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

1

जैसा कि गॉर्डन कहते हैं कि यह संभव नहीं है। लेकिन अगर आप एक स्ट्रिंग प्राप्त करने का एक तरीका ढूंढ रहे हैं जो कि किसी दिए गए वर्ग के उदाहरण के रूप में डिकोड किया जा सकता है, तो आप इसके बजाय क्रमबद्ध और अचयनित उपयोग कर सकते हैं ।

class Foo
{

    protected $bar = 'Hello World';

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

}

$string = serialize(new Foo);

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

यह प्रश्न को संबोधित नहीं करता है। यदि ऐसा होता है, तो आपको कुछ स्पष्टीकरण देना होगा।
फेलिक्स क्लिंग

1

मैंने एक बार इस उद्देश्य के लिए एक सार आधार वर्ग बनाया था। चलो इसे JsonConvertible कहते हैं। इसे जनता के सदस्यों को क्रमबद्ध करना चाहिए और उन्हें हताश करना चाहिए। यह प्रतिबिंब और देर से स्थिर बंधन का उपयोग करके संभव है।

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

बस स्मृति से, इसलिए शायद निर्दोष नहीं। आपको स्थैतिक गुणों को भी बाहर करना होगा और व्युत्पन्न वर्गों को कुछ गुणों को अनदेखा करने का मौका दे सकता है जब धारावाहिक में / से जस की तस। मुझे आशा है कि आपको यह विचार मिलेगा, फिर भी।


0

JSON विभिन्न प्रोग्रामिंग भाषाओं (और यह जावास्क्रिप्ट का एक सबसेट भी है) के बीच डेटा स्थानांतरित करने के लिए एक सरल प्रोटोकॉल है जो केवल कुछ प्रकारों का समर्थन करता है: नंबर, स्ट्रिंग्स, सरणियाँ / सूचियाँ, ऑब्जेक्ट्स / डाइक। ऑब्जेक्ट्स केवल कुंजी = मूल्य मानचित्र हैं और Arrays सूचियों का आदेश दिया गया है।

तो सामान्य तरीके से कस्टम ऑब्जेक्ट्स को व्यक्त करने का कोई तरीका नहीं है। समाधान एक संरचना को परिभाषित कर रहा है जहां आपके कार्यक्रम को पता चलेगा कि यह एक कस्टम वस्तु है।

यहाँ एक उदाहरण है:

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

इस का एक उदाहरण बनाने के लिए इस्तेमाल किया जा सकता है MyClassऔर खेतों सेट aऔर fooकरने के लिए 123और "bar"


6
यह सच हो सकता है, लेकिन यह सवाल सामान्य तरीके से वस्तुओं का प्रतिनिधित्व करने के बारे में नहीं पूछ रहा है। ऐसा लगता है कि उसे एक विशिष्ट JSON बैग मिला है जो एक या दोनों सिरों पर एक विशिष्ट वर्ग के लिए मैप करता है। इस कारण से आप JSON का उपयोग गैर-जेनेरिक नामित वर्गों के स्पष्ट क्रमांकन के रूप में नहीं कर सकते। यदि आप एक सामान्य समाधान चाहते हैं तो इसका नामकरण ठीक है, लेकिन JSON संरचना पर अनुबंध पर सहमत होने के साथ कुछ भी गलत नहीं है।
डग डब्लू २ Dou

यह काम कर सकता है यदि आप एन्कोडिंग छोर पर सीरियल को लागू करते हैं, और डिकोडिंग छोर पर सशर्त होते हैं। यदि ठीक से व्यवस्थित किया जाए तो उपवर्गों के साथ भी काम कर सकता है।
पीटर लेनजो

0

मैंने आगे बढ़कर जॉन पेटिट के जवाब को एक फ़ंक्शन ( जिस्ट ) के रूप में लागू किया :

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

यह मेरे उपयोग के मामले के लिए पूरी तरह से काम करता है। हालाँकि येवगेनी अफानसैयेव की प्रतिक्रिया मुझे समान रूप से आशाजनक लगती है। यह संभव हो सकता है कि आपकी कक्षा में एक अतिरिक्त "कंस्ट्रक्टर" हो, जैसे:

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

यह भी इस उत्तर से प्रेरित है ।


-1

मुझे लगता है कि सबसे सरल तरीका है:

function mapJSON($json, $class){
$decoded_object = json_decode($json);
   foreach ($decoded_object as $key => $value) {
            $class->$key = $value;
   }
   return $class;}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.