¿Puede explicarnos la licencia OSL3? Si utilizo JsonMapper en un sitio web, ¿debo publicar el código fuente de ese sitio web? Si utilizo JsonMapper en el código de un dispositivo que vendo, ¿debe ser todo el código de ese dispositivo de código abierto?
EricP
No, solo tienes que publicar los cambios que realices en el propio JsonMapper.
cweiske
29
Puedes hacerlo, es un torpe pero totalmente posible. Tuvimos que hacer cuando empezamos a almacenar cosas en la base del sofá.
$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
En nuestros puntos de referencia, esto fue mucho más rápido que intentar iterar a través de todas las variables de clase.
Advertencia: no funcionará para objetos anidados que no sean stdClass
Editar: tenga en cuenta la fuente de datos, se recomienda encarecidamente que no haga esto con datos no confiables de los usuarios sin un análisis muy cuidadoso de los riesgos.
¿Funciona esto con subclases encapsuladas? Por ejemplo { "a": {"b":"c"} }, ¿dónde el objeto aes de otra clase y no solo una matriz asociativa?
J-Rou
2
no, json_decode crea objetos stdclass, incluidos los subobjetos, si desea que sean cualquier otra cosa, debe modificar cada objeto como se indicó anteriormente.
John Pettitt
Gracias, eso es lo que imaginé
J-Rou
¿Qué tal si usamos esta solución en objetos donde el constructor tiene parámetros? No puedo conseguir que funcione. Esperaba que alguien pudiera señalarme en la dirección correcta para hacer que esta solución funcione con un objeto que tiene un constructor personalizado con parámetros.
La sintaxis no depende de la versión del serializador JMS, sino de la versión de PHP; a partir de PHP5.5 puede usar la ::classnotación: php.net/manual/en/…
Ivan Yarych
4
Puede hacer una envoltura para su objeto y hacer que la envoltura parezca que es el objeto en sí. Y funcionará con objetos multinivel.
<?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
Deserialización de JSON a Object: (este ejemplo usa XML solo para demostrar la flexibilidad de los formatos)
Como dice Gordon, no es posible. Pero si está buscando una forma de obtener una cadena que pueda decodificarse como una instancia de una clase determinada, puede usar serializar y unserializar en su lugar.
Esto no parece abordar la cuestión. Si es así, debe proporcionar alguna explicación.
Felix Kling
1
Una vez creé una clase base abstracta para este propósito. Llamémoslo JsonConvertible. Debe serializar y deserializar los miembros públicos. Esto es posible usando Reflection y enlace estático tardío.
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();
Solo de memoria, probablemente no sea impecable. También tendrá que excluir las propiedades estáticas y puede dar a las clases derivadas la oportunidad de hacer que algunas propiedades se ignoren cuando se serializan a / desde json. No obstante, espero que entiendas la idea.
JSON es un protocolo simple para transferir datos entre varios lenguajes de programación (y también es un subconjunto de JavaScript) que admite solo ciertos tipos: números, cadenas, matrices / listas, objetos / dictados. Los objetos son simplemente mapas clave = valor y las matrices son listas ordenadas.
Por tanto, no hay forma de expresar objetos personalizados de forma genérica. La solución es definir una estructura en la que su (s) programa (s) sabrán que es un objeto personalizado.
Esto puede ser cierto, pero la pregunta no es sobre la representación de objetos de forma genérica. Parece que tiene una bolsa JSON específica que se asigna a una clase específica en uno o ambos extremos. No hay ninguna razón por la que no pueda usar JSON como una serialización explícita de clases con nombre no genéricas de esta manera. Nombrarlo como lo está haciendo está bien si desea una solución genérica, pero tampoco hay nada de malo en tener un contrato acordado sobre la estructura JSON.
DougW
Esto podría funcionar si implementa Serializable en el extremo de la codificación y tiene condicionales en el extremo de la decodificación. Incluso podría funcionar con subclases si se organiza correctamente.
Esto funcionó perfectamente para mi caso de uso. Sin embargo, la respuesta de Yevgeniy Afanasyev me parece igualmente prometedora. Podría ser posible que su clase tenga un "constructor" adicional, así:
publicstaticfunctionwithJson(string $json) {
$instance = newstatic();
// Do your thingreturn $instance;
}
Respuestas:
No de forma automática. Pero puedes hacerlo por la ruta antigua.
$data = json_decode($json, true); $class = new Whatever(); foreach ($data as $key => $value) $class->{$key} = $value;
O, alternativamente, podría hacerlo más automático:
class Whatever { public function set($data) { foreach ($data AS $key => $value) $this->{$key} = $value; } } $class = new Whatever(); $class->set($data);
Editar : volviéndose un poco más elegante:
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);
fuente
Creamos JsonMapper para mapear objetos JSON en nuestras propias clases de modelo automáticamente. Funciona bien con objetos anidados / secundarios.
Solo se basa en la información de tipo docblock para el mapeo, que la mayoría de las propiedades de clase tienen de todos modos:
<?php $mapper = new JsonMapper(); $contactObject = $mapper->map( json_decode(file_get_contents('http://example.org/contact.json')), new Contact() ); ?>
fuente
Puedes hacerlo, es un torpe pero totalmente posible. Tuvimos que hacer cuando empezamos a almacenar cosas en la base del sofá.
$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
En nuestros puntos de referencia, esto fue mucho más rápido que intentar iterar a través de todas las variables de clase.
Advertencia: no funcionará para objetos anidados que no sean stdClass
Editar: tenga en cuenta la fuente de datos, se recomienda encarecidamente que no haga esto con datos no confiables de los usuarios sin un análisis muy cuidadoso de los riesgos.
fuente
{ "a": {"b":"c"} }
, ¿dónde el objetoa
es de otra clase y no solo una matriz asociativa?Puede utilizar la biblioteca Serializer de J ohannes Schmitt .
$serializer = JMS\Serializer\SerializerBuilder::create()->build(); $object = $serializer->deserialize($jsonData, 'MyNamespace\MyObject', 'json');
En la última versión del serializador JMS, la sintaxis es:
$serializer = SerializerBuilder::create()->build(); $object = $serializer->deserialize($jsonData, MyObject::class, 'json');
fuente
::class
notación: php.net/manual/en/…Puede hacer una envoltura para su objeto y hacer que la envoltura parezca que es el objeto en sí. Y funcionará con objetos multinivel.
<?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
fuente
No, esto no es posible a partir de PHP 5.5.1.
Lo único posible es tener
json_decode
matrices asociadas de retorno en lugar de los objetos StdClass.fuente
Puedes hacerlo de la siguiente manera.
<?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; } } } }
?>
Para obtener más detalles, visite create-custom-class-in-php-from-json-or-array
fuente
Me sorprende que nadie haya mencionado esto todavía.
Utilice el componente Serializador de Symfony: https://symfony.com/doc/current/components/serializer.html
Serializando de Object a 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
Deserialización de JSON a Object: (este ejemplo usa XML solo para demostrar la flexibilidad de los formatos)
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');
fuente
Utilice Reflexión :
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; }
fuente
Como dice Gordon, no es posible. Pero si está buscando una forma de obtener una cadena que pueda decodificarse como una instancia de una clase determinada, puede usar serializar y unserializar en su lugar.
class Foo { protected $bar = 'Hello World'; function getBar() { return $this->bar; } } $string = serialize(new Foo); $foo = unserialize($string); echo $foo->getBar();
fuente
Una vez creé una clase base abstracta para este propósito. Llamémoslo JsonConvertible. Debe serializar y deserializar los miembros públicos. Esto es posible usando Reflection y enlace estático tardío.
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();
Solo de memoria, probablemente no sea impecable. También tendrá que excluir las propiedades estáticas y puede dar a las clases derivadas la oportunidad de hacer que algunas propiedades se ignoren cuando se serializan a / desde json. No obstante, espero que entiendas la idea.
fuente
JSON es un protocolo simple para transferir datos entre varios lenguajes de programación (y también es un subconjunto de JavaScript) que admite solo ciertos tipos: números, cadenas, matrices / listas, objetos / dictados. Los objetos son simplemente mapas clave = valor y las matrices son listas ordenadas.
Por tanto, no hay forma de expresar objetos personalizados de forma genérica. La solución es definir una estructura en la que su (s) programa (s) sabrán que es un objeto personalizado.
He aquí un ejemplo:
{ "cls": "MyClass", fields: { "a": 123, "foo": "bar" } }
Esto podría usarse para crear una instancia de
MyClass
y establecer los camposa
yfoo
para123
y"bar"
.fuente
Seguí adelante e implementé la respuesta de John Petit , como una función ( esencia ):
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); }
Esto funcionó perfectamente para mi caso de uso. Sin embargo, la respuesta de Yevgeniy Afanasyev me parece igualmente prometedora. Podría ser posible que su clase tenga un "constructor" adicional, así:
public static function withJson(string $json) { $instance = new static(); // Do your thing return $instance; }
Esto también se inspira en esta respuesta .
fuente
Creo que la forma más sencilla es:
function mapJSON($json, $class){ $decoded_object = json_decode($json); foreach ($decoded_object as $key => $value) { $class->$key = $value; } return $class;}
fuente