serialize online objetos objeto metodos manejo ejemplo crear clases array php object json object-serialization

online - serialize php ejemplo



Serialización de objetos PHP a JSON (9)

Así que estaba vagando por php.net para obtener información sobre la serialización de objetos PHP a JSON, cuando tropecé con la nueva interfaz JsonSerializable . Sin embargo, solo PHP> = 5.4 y me 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 volcar el objeto de datos ( que de otra manera se enviaría a la vista ) a JSON sería perfecto.

Si intento serializar el objeto directamente, devuelve una cadena JSON vacía; que es porque supongo que json_encode() no sabe qué diablos hacer con el objeto. ¿Debo recursivamente reducir el objeto a una matriz, y luego codificar eso ?

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)

Esta es la función toArray() que he ideado para la clase Mf_Data :

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 objetos Mf_Data también tienen una referencia a su objeto primario (que contiene ), esto falla con la recursión. Aunque funciona como un amuleto cuando _parent referencia _parent .

2)

Solo para dar seguimiento, 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 siguiendo de nuevo, con un poco más limpio de una implementación. El uso de interfaces para una instanceof verificación parece mucho más limpio que method_exists() ( sin embargo, method_exists() tiene una herencia / implementación cross-cut ).

El uso de unset() parecía un poco desordenado, y parece que la lógica debe ser refactorizada en otro método. Sin embargo, esta implementación copia la matriz de propiedades ( debido a array_diff_key ), por lo que debe array_diff_key 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'' ))); } }


Como su tipo de objeto es personalizado, yo tendía a estar de acuerdo con su solución: descomponerlo en segmentos más pequeños usando un método de codificación (como JSON o serializar el contenido) y en el otro extremo, el código correspondiente para reconstruir el objeto.


El siguiente código está haciendo el trabajo usando la reflexión. Supone que tiene getters para las propiedades que desea serializar

<?php /** * Serialize a simple PHP object into json * Should be used for POPO that has getter methods for the relevant properties to serialize * A property can be simple or by itself another POPO object * * Class CleanJsonSerializer */ class CleanJsonSerializer { /** * Local cache of a property getters per class - optimize reflection code if the same object appears several times * @var array */ private $classPropertyGetters = array(); /** * @param mixed $object * @return string|false */ public function serialize($object) { return json_encode($this->serializeInternal($object)); } /** * @param $object * @return array */ private function serializeInternal($object) { if (is_array($object)) { $result = $this->serializeArray($object); } elseif (is_object($object)) { $result = $this->serializeObject($object); } else { $result = $object; } return $result; } /** * @param $object * @return /ReflectionClass */ private function getClassPropertyGetters($object) { $className = get_class($object); if (!isset($this->classPropertyGetters[$className])) { $reflector = new /ReflectionClass($className); $properties = $reflector->getProperties(); $getters = array(); foreach ($properties as $property) { $name = $property->getName(); $getter = "get" . ucfirst($name); try { $reflector->getMethod($getter); $getters[$name] = $getter; } catch (/Exception $e) { // if no getter for a specific property - ignore it } } $this->classPropertyGetters[$className] = $getters; } return $this->classPropertyGetters[$className]; } /** * @param $object * @return array */ private function serializeObject($object) { $properties = $this->getClassPropertyGetters($object); $data = array(); foreach ($properties as $name => $property) { $data[$name] = $this->serializeInternal($object->$property()); } return $data; } /** * @param $array * @return array */ private function serializeArray($array) { $result = array(); foreach ($array as $key => $value) { $result[$key] = $this->serializeInternal($value); } return $result; } }


En los casos más simples, la sugerencia de tipo debería funcionar:

$json = json_encode( (array)$object );


Hice una buena clase de ayuda que convierte un objeto con obtener métodos para una matriz. No se basa en propiedades, solo métodos.

Así que tengo un objeto de revisión siguiente que contiene dos métodos:

revisión

  • getAmountReviews: int
  • getReviews: matriz de comentarios

Comentario

  • getSubject
  • getDescription

El script que escribí lo transformará en una matriz con propiedades que se parece a esto:

{ amount_reviews: 21, reviews: [ { subject: "In een woord top 1!", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor." }, { subject: "En een zwembad 2!", description: "Maecenas et aliquet mi, a interdum mauris. Donec in egestas sem. Sed feugiat commodo maximus. Pellentesque porta consectetur commodo. Duis at finibus urna." }, { subject: "In een woord top 3!", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor." }, { subject: "En een zwembad 4!", description: "Maecenas et aliquet mi, a interdum mauris. Donec in egestas sem. Sed feugiat commodo maximus. Pellentesque porta consectetur commodo. Duis at finibus urna." }, { subject: "In een woord top 5!", description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque laoreet lacus quis eros venenatis, sed tincidunt mi rhoncus. Aliquam ut pharetra diam, nec lobortis dolor." } ]}

Fuente: Serializador de PHP que convierte un objeto en una matriz que se puede codificar a JSON.

Todo lo que tiene que hacer es ajustar json_encode alrededor de la salida.

Alguna información sobre el script:

  • Solo se agregan los métodos que comienzan con get
  • Los métodos privados son ignorados
  • Constructor es ignorado
  • Los caracteres de mayúscula en el nombre del método se reemplazarán por un guión bajo y un carácter en minúscula

Mi version:

json_encode(self::toArray($ob))

Implementación:

private static function toArray($object) { $reflectionClass = new /ReflectionClass($object); $properties = $reflectionClass->getProperties(); $array = []; foreach ($properties as $property) { $property->setAccessible(true); $value = $property->getValue($object); if (is_object($value)) { $array[$property->getName()] = self::toArray($value); } else { $array[$property->getName()] = $value; } } return $array; }

JsonUtils: GitHub


Pasé algunas horas con el mismo problema. Mi objetivo de conversión contiene muchos otros cuyas definiciones no debo tocar (API), así que se me ocurrió una solución que podría ser lenta, supongo, pero la estoy usando para fines de desarrollo.

Este convierte cualquier objeto a matriz

function objToArr($o) { $s = ''<?php class base { public static function __set_state($array) { return $array; } } function __autoload($class) { eval("class $class extends base {}"); } $a = ''.var_export($o,true).''; var_export($a); ''; $f = ''./tmp_''.uniqid().''.php''; file_put_contents($f,$s); chmod($f,0755); $r = eval(''return ''.shell_exec(''php -f ''.$f).'';''); unlink($f); return $r; }

Esto convierte cualquier objeto en stdClass

class base { public static function __set_state($array) { return (object)$array; } } function objToStd($o) { $s = ''<?php class base { public static function __set_state($array) { $o = new self; foreach($array as $k => $v) $o->$k = $v; return $o; } } function __autoload($class) { eval("class $class extends base {}"); } $a = ''.var_export($o,true).''; var_export($a); ''; $f = ''./tmp_''.uniqid().''.php''; file_put_contents($f,$s); chmod($f,0755); $r = eval(''return ''.shell_exec(''php -f ''.$f).'';''); unlink($f); return $r; }



json_encode() solo codificará las variables de miembro público. así que si quieres incluir lo privado una vez que tienes que hacerlo tú solo (como sugirieron los otros)


editar : actualmente es 2016-09-24, y PHP 5.4 ha sido lanzado el 2012-03-01, y el soporte ha finalizado el 2015-09-01. Aún así, esta respuesta parece ganar votos a favor. Si todavía está utilizando PHP <5.4, está creando un riesgo de seguridad y poniendo en peligro su proyecto . Si no tiene razones convincentes para quedarse en <5.4, o incluso 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

getJsonData(); una función, por ejemplo, llamada getJsonData(); , que devolvería una matriz, un objeto stdClass u otro objeto con parámetros visibles en lugar de privados / protegidos, y realizaría un json_encode($data->getJsonData()); . Básicamente, implemente la función desde 5.4, pero llámela a mano.

Algo así funcionaría, ya que se llama a get_object_vars() desde dentro de la clase, que tiene acceso a variables privadas / protegidas:

function getJsonData(){ $var = get_object_vars($this); foreach ($var as &$value) { if (is_object($value) && method_exists($value,''getJsonData'')) { $value = $value->getJsonData(); } } return $var; }