Czy możesz wyjaśnić licencję OSL3? Jeśli używam JsonMapper w witrynie internetowej, czy muszę udostępniać kod źródłowy tej witryny? Jeśli używam JsonMapper w kodzie na sprzedawanym przeze mnie urządzeniu, czy cały kod tego urządzenia musi być open source?
EricP
Nie, musisz tylko opublikować zmiany, które robisz, w samym JsonMapper.
cweiske
29
Możesz to zrobić - to niewyraźne, ale całkowicie możliwe. Musieliśmy to zrobić, kiedy zaczęliśmy przechowywać rzeczy na kanapie.
$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
W naszych testach porównawczych było to znacznie szybsze niż próba iteracji przez wszystkie zmienne klas.
Uwaga: nie będzie działać w przypadku obiektów zagnieżdżonych innych niż stdClass
Edycja: pamiętaj o źródle danych, zdecydowanie zaleca się, aby nie robić tego z niezaufanymi danymi od użytkowników bez bardzo dokładnej analizy ryzyka.
Czy to działa z hermetyzowanymi podklasami. Np. { "a": {"b":"c"} }Gdzie obiekt anależy do innej klasy, a nie tylko do tablicy asocjacyjnej?
J-Rou
2
nie, json_decode tworzy obiekty stdclass, w tym obiekty podrzędne, jeśli chcesz, aby były czymkolwiek innym, musisz skleić każdy obiekt jak powyżej.
John Pettitt
Dziękuję, tak sobie wyobrażałem
J-Rou
Co powiesz na użycie tego rozwiązania na obiektach, w których konstruktor ma parametry. Nie mogę zmusić tego do pracy. Miałem nadzieję, że ktoś wskaże mi właściwy kierunek, aby to rozwiązanie działało z obiektem, który ma niestandardowego konstruktora z parametrami.
Składnia nie zależy od wersji JMS Serializer, ale raczej od wersji PHP - zaczynając od PHP5.5 możesz użyć ::classnotacji: php.net/manual/en/ ...
Ivan Yarych
4
Możesz utworzyć opakowanie dla swojego obiektu i sprawić, że będzie wyglądać tak, jakby był samym obiektem. I będzie działać z obiektami wielopoziomowymi.
<?phpclassObj{
public $slave;
publicfunction__get($key) {
return property_exists ( $this->slave , $key ) ? $this->slave->{$key} : null;
}
publicfunction__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
<?phpclassCatalogProduct{
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;
}
}
}
}
useApp\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
Deserializacja z JSON do obiektu: (w tym przykładzie użyto XML tylko po to, aby zademonstrować elastyczność formatów)
Jak mówi Gordon, nie jest to możliwe. Ale jeśli szukasz sposobu na uzyskanie ciągu, który można zdekodować jako wystąpienie klasy podającej , możesz zamiast tego użyć serializacji i odserializacji.
To nie wydaje się odpowiadać na pytanie. Jeśli tak, musisz podać jakieś wyjaśnienie.
Felix Kling
1
W tym celu stworzyłem kiedyś abstrakcyjną klasę bazową. Nazwijmy to JsonConvertible. Powinien serializować i deserializować członków publicznych. Jest to możliwe dzięki zastosowaniu Reflection i późnego wiązania statycznego.
abstractclassJsonConvertible{
staticfunctionfromJson($json) {
$result = newstatic();
$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;
}
functiontoJson() {
return json_encode($this);
}
}
classMyClassextendsJsonConvertible{
public $name;
public $whatever;
}
$mine = MyClass::fromJson('{"name": "My Name", "whatever": "Whatever"}');
echo $mine->toJson();
Tylko z pamięci, więc prawdopodobnie nie bez wad. Będziesz także musiał wykluczyć właściwości statyczne i może dać klasom pochodnym szansę na zignorowanie niektórych właściwości podczas serializacji do / z json. Mam nadzieję, że mimo wszystko wpadniesz na pomysł.
JSON to prosty protokół do przesyłania danych między różnymi językami programowania (a także podzbiorem JavaScript), który obsługuje tylko niektóre typy: liczby, ciągi znaków, tablice / listy, obiekty / dykty. Obiekty to po prostu mapy klucz = wartość, a tablice to uporządkowane listy.
Dlatego nie ma możliwości wyrażenia obiektów niestandardowych w sposób ogólny. Rozwiązaniem jest zdefiniowanie struktury, w której program (y) będzie wiedział, że jest to obiekt niestandardowy.
Może to prawda, ale pytanie nie dotyczy przedstawiania obiektów w ogólny sposób. Wygląda na to, że ma określoną torbę JSON, która mapuje do określonej klasy na jednym lub obu końcach. Nie ma powodu, dla którego nie można w ten sposób używać formatu JSON jako jawnej serializacji nieogólnych nazwanych klas. Nazwanie go tak, jak to robisz, jest w porządku, jeśli chcesz uzyskać ogólne rozwiązanie, ale nie ma też nic złego w posiadaniu uzgodnionej umowy dotyczącej struktury JSON.
DougW
Może to zadziałać, jeśli zaimplementujesz Serializable na końcu kodowania i masz warunki warunkowe na końcu dekodowania. Może nawet działać z podklasami, jeśli są odpowiednio zorganizowane.
Peter Lenjo
0
Poszedłem dalej i zaimplementowałem odpowiedź Johna Petita jako funkcję ( sedno ):
To działało idealnie w moim przypadku użycia. Jednak odpowiedź Jewgienija Afanasjewa wydaje mi się równie obiecująca. Możliwe, że Twoja klasa będzie miała dodatkowego „konstruktora”, na przykład:
publicstaticfunctionwithJson(string $json) {
$instance = newstatic();
// Do your thingreturn $instance;
}
Odpowiedzi:
Nie automatycznie. Ale możesz to zrobić staromodną trasą.
$data = json_decode($json, true); $class = new Whatever(); foreach ($data as $key => $value) $class->{$key} = $value;
Lub możesz zrobić to bardziej automatycznie:
class Whatever { public function set($data) { foreach ($data AS $key => $value) $this->{$key} = $value; } } $class = new Whatever(); $class->set($data);
Edycja : trochę bardziej wyszukana:
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);
źródło
Zbudowaliśmy JsonMapper, aby automatycznie mapować obiekty JSON na nasze własne klasy modelu. Działa dobrze z obiektami zagnieżdżonymi / podrzędnymi.
Opiera się tylko na informacjach o typie docblock do mapowania, które i tak ma większość właściwości klas:
<?php $mapper = new JsonMapper(); $contactObject = $mapper->map( json_decode(file_get_contents('http://example.org/contact.json')), new Contact() ); ?>
źródło
Możesz to zrobić - to niewyraźne, ale całkowicie możliwe. Musieliśmy to zrobić, kiedy zaczęliśmy przechowywać rzeczy na kanapie.
$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
W naszych testach porównawczych było to znacznie szybsze niż próba iteracji przez wszystkie zmienne klas.
Uwaga: nie będzie działać w przypadku obiektów zagnieżdżonych innych niż stdClass
Edycja: pamiętaj o źródle danych, zdecydowanie zaleca się, aby nie robić tego z niezaufanymi danymi od użytkowników bez bardzo dokładnej analizy ryzyka.
źródło
{ "a": {"b":"c"} }
Gdzie obiekta
należy do innej klasy, a nie tylko do tablicy asocjacyjnej?Możesz użyć biblioteki Serializer J ohannesa Schmitta .
$serializer = JMS\Serializer\SerializerBuilder::create()->build(); $object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json');
W najnowszej wersji serializatora JMS składnia jest następująca:
$serializer = SerializerBuilder::create()->build(); $object = $serializer->deserialize($jsonData, MyObject::class, 'json');
źródło
::class
notacji: php.net/manual/en/ ...Możesz utworzyć opakowanie dla swojego obiektu i sprawić, że będzie wyglądać tak, jakby był samym obiektem. I będzie działać z obiektami wielopoziomowymi.
<?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
źródło
Nie, od wersji PHP 5.5.1 nie jest to możliwe.
Jedyną możliwą rzeczą jest
json_decode
zwrócenie tablic skojarzonych zamiast obiektów StdClass.źródło
Możesz to zrobić poniżej.
<?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; } } } }
?>
Aby uzyskać więcej informacji, odwiedź stronę create-custom-class-in-php-from-json-or-array
źródło
Dziwię się, że nikt jeszcze o tym nie wspomniał.
Użyj komponentu Symfony Serializer: https://symfony.com/doc/current/components/serializer.html
Serializacja z obiektu do 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
Deserializacja z JSON do obiektu: (w tym przykładzie użyto XML tylko po to, aby zademonstrować elastyczność formatów)
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');
źródło
Użyj odbicia :
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; }
źródło
Jak mówi Gordon, nie jest to możliwe. Ale jeśli szukasz sposobu na uzyskanie ciągu, który można zdekodować jako wystąpienie klasy podającej , możesz zamiast tego użyć serializacji i odserializacji.
class Foo { protected $bar = 'Hello World'; function getBar() { return $this->bar; } } $string = serialize(new Foo); $foo = unserialize($string); echo $foo->getBar();
źródło
W tym celu stworzyłem kiedyś abstrakcyjną klasę bazową. Nazwijmy to JsonConvertible. Powinien serializować i deserializować członków publicznych. Jest to możliwe dzięki zastosowaniu Reflection i późnego wiązania statycznego.
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();
Tylko z pamięci, więc prawdopodobnie nie bez wad. Będziesz także musiał wykluczyć właściwości statyczne i może dać klasom pochodnym szansę na zignorowanie niektórych właściwości podczas serializacji do / z json. Mam nadzieję, że mimo wszystko wpadniesz na pomysł.
źródło
JSON to prosty protokół do przesyłania danych między różnymi językami programowania (a także podzbiorem JavaScript), który obsługuje tylko niektóre typy: liczby, ciągi znaków, tablice / listy, obiekty / dykty. Obiekty to po prostu mapy klucz = wartość, a tablice to uporządkowane listy.
Dlatego nie ma możliwości wyrażenia obiektów niestandardowych w sposób ogólny. Rozwiązaniem jest zdefiniowanie struktury, w której program (y) będzie wiedział, że jest to obiekt niestandardowy.
Oto przykład:
{ "cls": "MyClass", fields: { "a": 123, "foo": "bar" } }
Można to wykorzystać do utworzenia wystąpienia
MyClass
i ustawienia póla
orazfoo
do123
i"bar"
.źródło
Poszedłem dalej i zaimplementowałem odpowiedź Johna Petita jako funkcję ( sedno ):
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); }
To działało idealnie w moim przypadku użycia. Jednak odpowiedź Jewgienija Afanasjewa wydaje mi się równie obiecująca. Możliwe, że Twoja klasa będzie miała dodatkowego „konstruktora”, na przykład:
public static function withJson(string $json) { $instance = new static(); // Do your thing return $instance; }
To również jest inspirowane tą odpowiedzią .
źródło
Myślę, że najprostszy sposób to:
function mapJSON($json, $class){ $decoded_object = json_decode($json); foreach ($decoded_object as $key => $value) { $class->$key = $value; } return $class;}
źródło