Apakah mungkin untuk memecahkan kode string json ke objek selain stdClass?
Apakah mungkin untuk memecahkan kode string json ke objek selain stdClass?
Jawaban:
Tidak otomatis. Tapi Anda bisa melakukannya dengan cara lama.
$data = json_decode($json, true);
$class = new Whatever();
foreach ($data as $key => $value) $class->{$key} = $value;
Atau sebagai alternatif, Anda dapat membuatnya lebih otomatis:
class Whatever {
public function set($data) {
foreach ($data AS $key => $value) $this->{$key} = $value;
}
}
$class = new Whatever();
$class->set($data);
Sunting : menjadi sedikit lebih menarik:
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);
Kami membangun JsonMapper untuk memetakan objek JSON ke kelas model kami sendiri secara otomatis. Ini berfungsi dengan baik dengan objek bersarang / anak.
Ini hanya bergantung pada informasi jenis docblock untuk pemetaan, yang kebanyakan properti kelas miliki:
<?php
$mapper = new JsonMapper();
$contactObject = $mapper->map(
json_decode(file_get_contents('http://example.org/contact.json')),
new Contact()
);
?>
Anda bisa melakukannya - itu kludge tetapi sangat mungkin. Kami harus melakukannya ketika kami mulai menyimpan barang-barang di 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
Dalam tolok ukur kami, ini jauh lebih cepat daripada mencoba mengulang melalui semua variabel kelas.
Peringatan: Tidak akan berfungsi untuk objek bertingkat selain stdClass
Edit: perhatikan sumber data, sangat disarankan agar Anda tidak melakukan ini dengan data tidak tepercaya dari pengguna tanpa analisis risiko yang cermat.
{ "a": {"b":"c"} }
, di mana objeknya a
adalah kelas lain dan bukan hanya array asosiatif?
Anda dapat menggunakan pustaka Serializer J ohannes Schmitt .
$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json');
Dalam versi terbaru serializer JMS, sintaksnya adalah:
$serializer = SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, MyObject::class, 'json');
::class
notasi: php.net/manual/en/…
Anda dapat membuat pembungkus untuk objek Anda dan membuat pembungkus terlihat seperti objek itu sendiri. Dan itu akan bekerja dengan objek bertingkat.
<?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
Tidak, ini tidak mungkin dilakukan mulai PHP 5.5.1.
Satu-satunya hal yang mungkin adalah memiliki json_decode
array asosiasi yang dikembalikan, bukan objek StdClass.
Anda dapat melakukannya dengan cara di bawah ini ..
<?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;
}
}
}
}
?>
Untuk detail selengkapnya, kunjungi create-custom-class-in-php-from-json-or-array
Saya terkejut belum ada yang menyebutkan ini.
Gunakan komponen Symfony Serializer: https://symfony.com/doc/current/components/serializer.html
Membuat serial dari Object ke 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
Deserialisasi dari JSON ke Objek: (contoh ini menggunakan XML hanya untuk mendemonstrasikan fleksibilitas format)
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');
Gunakan Refleksi :
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;
}
Seperti yang dikatakan Gordon, itu tidak mungkin. Tetapi jika Anda mencari cara untuk mendapatkan string yang dapat didekode sebagai instance dari kelas give, Anda dapat menggunakan serialize dan unserialize sebagai gantinya.
class Foo
{
protected $bar = 'Hello World';
function getBar() {
return $this->bar;
}
}
$string = serialize(new Foo);
$foo = unserialize($string);
echo $foo->getBar();
Saya pernah membuat kelas dasar abstrak untuk tujuan ini. Sebut saja JsonConvertible. Ini harus membuat serial dan deserialisasi anggota publik. Hal ini dimungkinkan dengan menggunakan Refleksi dan pengikatan statis akhir.
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();
Hanya dari ingatan, jadi mungkin tidak sempurna. Anda juga harus mengecualikan properti statis dan mungkin memberi kelas turunan kesempatan untuk membuat beberapa properti diabaikan saat diserialkan ke / dari json. Meski begitu, saya harap Anda mengerti.
JSON adalah protokol sederhana untuk mentransfer data antara berbagai bahasa pemrograman (dan itu juga merupakan bagian dari JavaScript) yang hanya mendukung jenis tertentu: angka, string, array / daftar, objek / dicts. Objek hanyalah peta key = value dan Array adalah daftar yang diurutkan.
Jadi tidak ada cara untuk mengekspresikan objek khusus dengan cara yang umum. Solusinya adalah dengan menentukan struktur di mana program Anda akan tahu bahwa itu adalah objek khusus.
Berikut contohnya:
{ "cls": "MyClass", fields: { "a": 123, "foo": "bar" } }
Ini dapat digunakan untuk membuat instance dari MyClass
dan mengatur bidang a
dan foo
ke 123
dan "bar"
.
Saya melanjutkan dan menerapkan jawaban John Petit , sebagai fungsi ( inti ):
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);
}
Ini bekerja dengan sempurna untuk kasus penggunaan saya. Namun tanggapan Yevgeniy Afanasyev tampaknya sama menjanjikannya bagi saya. Mungkin saja kelas Anda memiliki "konstruktor" tambahan, seperti:
public static function withJson(string $json) {
$instance = new static();
// Do your thing
return $instance;
}
Ini juga terinspirasi oleh jawaban ini .
EDIT: Saya telah menggunakan karriereat / json-decoder untuk beberapa waktu sekarang, dan saya sama sekali tidak mengalami masalah dengannya. Ringan dan sangat mudah dikembangkan. Berikut adalah contoh pengikatan yang saya tulis untuk deserialisasi JSON menjadi objek Carbon / CarbonImmutable.