Bir json dizesini stdClass dışında bir nesneye çözmek mümkün müdür?
Bir json dizesini stdClass dışında bir nesneye çözmek mümkün müdür?
Yanıtlar:
Otomatik olarak değil. Ama bunu eski moda yoldan yapabilirsiniz.
$data = json_decode($json, true);
$class = new Whatever();
foreach ($data as $key => $value) $class->{$key} = $value;
Veya alternatif olarak, bunu daha otomatik hale getirebilirsiniz:
class Whatever {
public function set($data) {
foreach ($data AS $key => $value) $this->{$key} = $value;
}
}
$class = new Whatever();
$class->set($data);
Düzenleme : Biraz meraklı olmak:
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);
Biz inşa JsonMapper otomatik kendi modeli sınıfları üzerine JSON işlevleri gerçekleştirilmektedir. İç içe / alt nesnelerle iyi çalışır.
Yalnızca eşleme için docblock türü bilgilerine dayanır; bu, çoğu sınıf özelliğinde zaten vardır:
<?php
$mapper = new JsonMapper();
$contactObject = $mapper->map(
json_decode(file_get_contents('http://example.org/contact.json')),
new Contact()
);
?>
Yapabilirsiniz - bu bir kludge ama tamamen mümkün. Bir şeyleri kanepe tabanında depolamaya başladığımızda yapmak zorundaydık.
$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
Kıyaslamalarımızda bu, tüm sınıf değişkenlerini yinelemeye çalışmaktan çok daha hızlıydı.
Uyarı: stdClass dışındaki iç içe nesneler için çalışmaz
Düzenleme: Veri kaynağını aklınızda bulundurun, bunu risklerin çok dikkatli bir analizi yapılmadan kullanıcılardan gelen güvenilmeyen verilerle yapmamanız şiddetle tavsiye edilir.
{ "a": {"b":"c"} }
, nesnenin a
başka bir sınıfta olduğu ve yalnızca ilişkilendirilebilir bir dizi olmadığı durumda?
J ohannes Schmitt'in Serializer kitaplığını kullanabilirsiniz .
$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json');
JMS serileştiricinin en son sürümünde sözdizimi şu şekildedir:
$serializer = SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonData, MyObject::class, 'json');
::class
gösterimi kullanabilirsiniz : php.net/manual/en/…
Nesneniz için bir sarmalayıcı yapabilir ve sarmalayıcının nesnenin kendisi gibi görünmesini sağlayabilirsiniz. Ve çok düzeyli nesnelerle çalışacaktır.
<?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
Hayır, bu PHP 5.5.1'den itibaren mümkün değildir.
Mümkün olan tek şey json_decode
, StdClass nesneleri yerine döndürülen ilişkili dizilere sahip olmaktır.
Bunu aşağıdaki şekilde yapabilirsiniz ..
<?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;
}
}
}
}
?>
Daha fazla ayrıntı için, json veya diziden-php-içinde-özel-sınıf oluşturma sayfasını ziyaret edin
Henüz kimsenin bundan bahsetmediğine şaşırdım.
Symfony Serializer bileşenini kullanın: https://symfony.com/doc/current/components/serializer.html
Nesneden JSON'a seri hale getirme:
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'dan Nesneye seriyi kaldırma: (bu örnek, yalnızca formatların esnekliğini göstermek için XML kullanır)
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');
Yansımayı Kullan :
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;
}
Gordon'un dediği gibi mümkün değil. Ancak, bir ver sınıfının örneği olarak kodu çözülebilecek bir dizge elde etmenin bir yolunu arıyorsanız, bunun yerine serileştirme ve serileştirmeyi kullanabilirsiniz .
class Foo
{
protected $bar = 'Hello World';
function getBar() {
return $this->bar;
}
}
$string = serialize(new Foo);
$foo = unserialize($string);
echo $foo->getBar();
Bir keresinde bu amaçla soyut bir temel sınıf yaratmıştım. Buna JsonConvertible diyelim. Kamu üyelerini seri hale getirmeli ve serisini kaldırmalıdır. Bu, Yansıma ve geç statik bağlama kullanılarak mümkündür.
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();
Sadece hafızadan, bu yüzden muhtemelen kusursuz değil. Ayrıca, statik özellikleri hariç tutmanız gerekecek ve türetilmiş sınıflara, json'a / json'dan serileştirildiğinde bazı özellikleri göz ardı etme şansı verebilirsiniz. Umarım yine de anlarsın.
JSON, yalnızca belirli türleri destekleyen çeşitli programlama dilleri (ve aynı zamanda bir JavaScript alt kümesidir) arasında veri aktarımı için basit bir protokoldür: sayılar, dizeler, diziler / listeler, nesneler / dikteler. Nesneler sadece anahtar = değer eşlemleridir ve Diziler sıralı listelerdir.
Bu nedenle, özel nesneleri genel bir şekilde ifade etmenin bir yolu yoktur. Çözüm, programlarınızın özel bir nesne olduğunu bilecekleri bir yapı tanımlamaktır.
İşte bir örnek:
{ "cls": "MyClass", fields: { "a": 123, "foo": "bar" } }
Bu bir örneğini oluşturmak için kullanılabilecek MyClass
ve alanları ayarlamak a
ve foo
karşı 123
ve "bar"
.
Devam ettim ve John Petit'in cevabını bir işlev ( özet ) olarak uyguladım :
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);
}
Bu benim kullanım durumum için mükemmel çalıştı. Ancak Yevgeniy Afanasyev'in yanıtı da bana aynı derecede umut verici görünüyor. Sınıfınızın ekstra bir "kurucu" sahibi olması mümkün olabilir, örneğin:
public static function withJson(string $json) {
$instance = new static();
// Do your thing
return $instance;
}
Bu aynı zamanda bu cevaptan da esinlenmiştir .
DÜZENLEME: Bir süredir karriereat / json-decoder kullanıyorum ve kesinlikle hiçbir sorun yaşamadım. Hafiftir ve çok kolay genişletilebilir. JSON'u bir Carbon / CarbonImmutable nesnesine seri durumdan çıkarmak için yazdığım bir bağlama örneği .