Así que estaba deambulando por php.net en busca de información sobre la serialización de objetos PHP en JSON, cuando me encontré con la nueva interfaz JsonSerializable . Sin embargo, es solo PHP> = 5.4 y estoy ejecutando en un entorno 5.3.x.
¿Cómo se logra este tipo de funcionalidad PHP <5.4 ?
Todavía no he trabajado mucho con JSON, pero estoy tratando de admitir una capa de API en una aplicación, y descargar el objeto de datos ( que de otro modo se enviaría a la vista ) en JSON sería perfecto.
Si intento serializar el objeto directamente, devuelve una cadena JSON vacía; que se debe a que supongo json_encode()
que no sabe qué diablos hacer con el objeto. ¿Debo recursivamente reducir el objeto en una matriz, y luego codificar que ?
Ejemplo
$data = new Mf_Data();
$data->foo->bar['hello'] = 'world';
echo json_encode($data)
produce un objeto vacío:
{}
var_dump($data)
sin embargo, funciona como se esperaba:
object(Mf_Data)#1 (5) {
["_values":"Mf_Data":private]=>
array(0) {
}
["_children":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["foo"]=>
object(Mf_Data)#2 (5) {
["_values":"Mf_Data":private]=>
array(0) {
}
["_children":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["bar"]=>
object(Mf_Data)#3 (5) {
["_values":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["hello"]=>
string(5) "world"
}
}
["_children":"Mf_Data":private]=>
array(0) {
}
["_parent":"Mf_Data":private]=>
*RECURSION*
["_key":"Mf_Data":private]=>
string(3) "bar"
["_index":"Mf_Data":private]=>
int(0)
}
}
}
["_parent":"Mf_Data":private]=>
*RECURSION*
["_key":"Mf_Data":private]=>
string(3) "foo"
["_index":"Mf_Data":private]=>
int(0)
}
}
}
["_parent":"Mf_Data":private]=>
NULL
["_key":"Mf_Data":private]=>
NULL
["_index":"Mf_Data":private]=>
int(0)
}
Apéndice
1)
Entonces esta es la toArray()
función que he ideado para la Mf_Data
clase:
public function toArray()
{
$array = (array) $this;
array_walk_recursive($array, function (&$property) {
if ($property instanceof Mf_Data) {
$property = $property->toArray();
}
});
return $array;
}
Sin embargo, dado que los Mf_Data
objetos también tienen una referencia a su objeto principal ( contenedor ), esto falla con la recursividad. Sin embargo, funciona como un encanto cuando elimino la _parent
referencia.
2)
Solo para continuar, la función final para transformar un objeto complejo de nodo de árbol con el que fui fue:
// class name - Mf_Data
// exlcuded properties - $_parent, $_index
public function toArray()
{
$array = get_object_vars($this);
unset($array['_parent'], $array['_index']);
array_walk_recursive($array, function (&$property) {
if (is_object($property) && method_exists($property, 'toArray')) {
$property = $property->toArray();
}
});
return $array;
}
3)
Estoy haciendo un seguimiento de nuevo, con una implementación un poco más limpia. El uso de interfaces para una instanceof
verificación parece mucho más limpio que method_exists()
( sin embargo method_exists()
, la herencia / implementación transversal ).
El uso también unset()
parecía un poco complicado, y parece que la lógica debería refactorizarse en otro método. Sin embargo, esta aplicación hace copiar la matriz de propiedad ( debido aarray_diff_key
), por lo que algo a tener en cuenta.
interface ToMapInterface
{
function toMap();
function getToMapProperties();
}
class Node implements ToMapInterface
{
private $index;
private $parent;
private $values = array();
public function toMap()
{
$array = $this->getToMapProperties();
array_walk_recursive($array, function (&$value) {
if ($value instanceof ToMapInterface) {
$value = $value->toMap();
}
});
return $array;
}
public function getToMapProperties()
{
return array_diff_key(get_object_vars($this), array_flip(array(
'index', 'parent'
)));
}
}
fuente
JsonSerializable
Respuestas:
editar : actualmente es 2016-09-24, PHP 5.4 ha sido lanzado 2012-03-01, y el soporte ha finalizado 2015-09-01. Aún así, esta respuesta parece ganar votos positivos. Si todavía usa PHP <5.4, está creando un riesgo de seguridad y poniendo en peligro su proyecto . Si no tiene razones convincentes para permanecer en <5.4, o incluso si ya usa la versión> = 5.4, no use esta respuesta , y simplemente use PHP> = 5.4 (o, ya sabe, uno reciente) e implemente la interfaz JsonSerializable
Definiría una función, por ejemplo nombrada
getJsonData();
, que devolvería una matriz, unstdClass
objeto o algún otro objeto con parámetros visibles en lugar de privados / protegidos, y haría unjson_encode($data->getJsonData());
. En esencia, implemente la función de 5.4, pero llámela a mano.Algo como esto funcionaría, como
get_object_vars()
se llama desde dentro de la clase, teniendo acceso a variables privadas / protegidas:fuente
stdClass
? Estoy pensando en la dirección de Reflexión , pero si no, simplemente encontraré algo para realizarlo de forma recursiva.getJsonData()
función, puede simplemente llamarget_object_vars()
y recorrer ese resultado buscando más objetos._parent
propiedad para que el árbol pueda atravesarse hasta la raíz. Vea mi edición para una actualización; tal vez debería hacer otra pregunta, ya que este tema ahora se abstrae de mi original.unset($array['_parent']);
antes de la caminata debería ser suficiente.$parent
como datos de usuario aarray_walk_recursive()
. ¡Lo simple es hermoso! Además, es$array["\0class\0property"]
debido a la contaminación de byte nulo porque estaba usando fundición. Creo que cambiaré aget_object_vars()
.En los casos más simples, las sugerencias de tipo deberían funcionar:
fuente
json_encode()
solo codificará las variables de miembros públicos. Entonces, si desea incluir lo privado una vez, debe hacerlo usted mismo (como sugirieron los demás)fuente
El siguiente código está haciendo el trabajo usando la reflexión. Asume que tiene captadores para las propiedades que desea serializar
fuente
Simplemente implemente una interfaz proporcionada por PHP JsonSerializable .
fuente
Dado que su tipo de objeto es personalizado, tendería a estar de acuerdo con su solución: dividirlo en segmentos más pequeños utilizando un método de codificación (como JSON o serializar el contenido) y, en el otro extremo, tener el código correspondiente para reconstruir el objeto.
fuente
Mi version:
Implementación:
JsonUtils: GitHub
fuente
Intenta usar esto, esto funcionó bien para mí.
fuente
Cambie a sus tipos de variables
private
parapublic
Esto es simple y más legible.
Por ejemplo
No funciona;
Está funcionando;
fuente
Hice una buena clase auxiliar que convierte un objeto con métodos get en una matriz. No se basa en propiedades, solo métodos.
Entonces tengo el siguiente objeto de revisión que contiene dos métodos:
revisión
Comentario
El script que escribí lo transformará en una matriz con propiedades que se parecen a esto:
Fuente: Serializador de PHP que convierte un objeto en una matriz que se puede codificar en JSON.
Todo lo que tiene que hacer es envolver json_encode alrededor de la salida.
Alguna información sobre el guión:
fuente
Pasé algunas horas con el mismo problema. Mi objeto para convertir contiene muchas otras cuyas definiciones se supone que no debo tocar (API), así que se me ocurrió una solución que podría ser lenta, supongo, pero la estoy usando con fines de desarrollo.
Este convierte cualquier objeto en matriz.
Esto convierte cualquier objeto a stdClass
fuente
unlink($thisAnswer);