Toma datos recuperados de un servicio web JSON y los convierte en objetos y matrices anidados, utilizando sus propias clases de modelo.
A partir de un objeto base, asigna datos JSON a propiedades de clase y los convierte en tipos u objetos simples correctos.
Es un poco como el mapeo de parámetros SOAP nativo que le brinda SoapClient
de PHP, pero para JSON. No depende de ningún esquema, sólo de las definiciones de sus clases PHP.
La detección de tipos funciona analizando declaraciones de tipos y anotaciones @var
docblock de propiedades de clase, así como sugerencias de tipos en métodos de establecimiento.
No es necesario modificar las clases de su modelo agregando código JSON específico; Funciona automáticamente analizando bloques de documentos ya existentes.
Esta biblioteca no tiene dependencias.
Palabras clave: deserialización, hidratación.
Contenido
map()
Las clases modelo deben escribirse a mano.
Dado que JsonMapper no se basa en ninguna información de esquema (por ejemplo, de json-schema), las clases de modelo no se pueden generar automáticamente.
netresearch/jsonmapper
con compositorJsonMapper
map
o mapArray
, dependiendo de sus datosMapear un objeto normal:
<?php
require ' autoload.php ' ;
$ mapper = new JsonMapper ();
$ contactObject = $ mapper -> map ( $ jsonContact , new Contact ());
// or as classname
$ contactObject = $ mapper -> map ( $ jsonContact , Contact::class);
Mapee una variedad de objetos:
<?php
require ' autoload.php ' ;
$ mapper = new JsonMapper ();
$ contactsArray = $ mapper -> mapArray (
$ jsonContacts , array (), ' Contact '
);
En lugar de array()
también puedes usar ArrayObject
y clases derivadas, así como clases que implementen ArrayAccess
.
JSON de un servicio web de libreta de direcciones:
{
"name" : "Sheldon Cooper" ,
"address" : {
"street" : "2311 N. Los Robles Avenue" ,
"city" : "Pasadena"
}
}
Su clase Contact
local:
<?php
class Contact
{
/**
* Full name
*/
public string $ name ;
public ? Address $ address ;
}
Su clase Address
local:
<?php
class Address
{
public $ street ;
public $ city ;
public function getGeoCoords ()
{
//do something with $street and $city
}
}
Su código de aplicación:
<?php
$ json = json_decode ( file_get_contents ( ' http://example.org/sheldon.json ' ));
$ mapper = new JsonMapper ();
$ contact = $ mapper -> map ( $ json , new Contact ());
echo " Geo coordinates for " . $ contact -> name . " : "
. var_export ( $ contact -> address -> getGeoCoords (), true );
JsonMapper
utiliza varias fuentes para detectar el tipo correcto de propiedad en el siguiente orden:
Método de establecimiento ( set
+ ucwords($propertyname)
)
Los guiones bajos " _
" y los guiones " -
" hacen que la siguiente letra esté en mayúscula. La propiedad foo_bar-baz
conduce al método de establecimiento setFooBarBaz
.
Si tiene una sugerencia de tipo en la firma del método, entonces se utiliza su tipo:
función pública setPerson(Contacto $persona) {...}
El bloque de documentos del método se inspecciona en busca de anotaciones @param $type
:
/** * @param Contacto $person Contacto principal para esta aplicación */ función pública setPersona($persona) {...}
Si no se pudo detectar ningún tipo, el valor JSON simple se pasa al método de establecimiento.
Tipos de propiedades de clase (desde PHP 7.4):
Contacto público $persona;
Tipos de promoción de propiedades de constructor (desde PHP 8.0):
función pública __construct(Contacto protegido $persona) {}
@var $type
docblock anotación de propiedades de clase:
/** * @var miaplicaciónmodeloContacto */ persona pública $;
La propiedad tiene que ser pública para ser utilizada directamente. También puede utilizar $bIgnoreVisibility para utilizar propiedades privadas y protegidas.
Si no se pudo detectar ningún tipo, la propiedad obtiene el valor JSON simple establecido.
Si no se puede encontrar una propiedad, JsonMapper intenta encontrarla sin distinguir entre mayúsculas y minúsculas. Una propiedad JSON isempty
se asignaría a una propiedad PHP isEmpty
.
Nota
Debe proporcionar el espacio de nombres completo para que el tipo funcione. Los nombres de clases relativos se evalúan en el contexto del espacio de nombres de clases actual, SIN respetar ninguna importación que pueda estar presente.
PHP no proporciona las importaciones a través de Reflection; el texto del comentario solo contiene el texto literal del tipo. Por motivos de rendimiento, JsonMapper no analiza el código fuente por sí solo para detectar y expandir cualquier importación.
tipos simples
string
bool
boolean
int
, integer
double
, float
array
object
mixed
Nombres de clases, con y sin espacios de nombres.
Contact
: se generará una excepción si el valor JSON es null
Matrices de tipos simples y nombres de clases:
int[]
Contact[]
Matrices multidimensionales:
int[][]
TreeDeePixel[][][]
ArrayObjects de tipos simples y nombres de clases:
ContactList[Contact]
NumberList[int]
Enumeraciones respaldadas, con y sin espacios de nombres
Suit:string|Suit:int
: se generará una excepción si el valor JSON no está presente en la enumeración
Tipos que aceptan valores NULL:
int|null
o ?int
: será null
si el valor en JSON es null
; de lo contrario, será un número enteroContact|null
o ?Contact
: será null
si el valor en JSON es null
; de lo contrario, será un objeto de tipo Contact
Los ArrayObjects y las clases extendidas se tratan como matrices.
Las variables sin tipo o con tipos mixed
obtendrán el valor JSON establecido directamente sin ninguna conversión.
Consulte la documentación de tipos de phpdoc para obtener más información.
Nota
Esta característica está deshabilitada de forma predeterminada por razones de seguridad desde la versión 5. Consulte $bStrictObjectTypeChecking para obtener más detalles.
Cuando se crea un objeto pero el JSON contiene sólo un tipo simple (por ejemplo, cadena, flotante, booleano), este valor se pasa al constructor de la clase. Ejemplo:
código PHP:
public DateTime $ date ;
JSON:
{ "date" : "2014-05-15" }
Esto dará como resultado que se llame a new DateTime('2014-05-15')
.
Cuando las variables se definen como objetos de clases o interfaces abstractas, JsonMapper normalmente intentaría crear una instancia de ellas directamente y fallaría.
Usando la propiedad $classMap
de JsonMapper, puede especificar qué clases se crearán instancias en su lugar:
$ jm = new JsonMapper ();
$ jm -> classMap [ ' Foo ' ] = ' Bar ' ;
$ jm -> map (...);
Esto crearía objetos de tipo Bar
cuando una variable se define como de tipo Foo
.
También es posible utilizar un invocable en caso de que la clase de implementación real deba determinarse dinámicamente (por ejemplo, en el caso de una unión). La clase asignada ('Foo' en el ejemplo siguiente) y los datos Json se pasan como parámetros en la llamada.
$ mapper = function ( $ class , $ jvalue ) {
// examine $class and $jvalue to figure out what class to use...
return ' DateTime ' ;
};
$ jm = new JsonMapper ();
$ jm -> classMap [ ' Foo ' ] = $ mapper ;
$ jm -> map (...);
JsonMapper genera una excepción cuando una propiedad JSON es null
, a menos que la propiedad de clase PHP tenga un tipo que acepte valores NULL, por ejemplo, Contact|null
o ?Contact
.
Si su API contiene muchos campos que pueden ser null
y no desea que todas sus definiciones de tipo sean anulables, establezca:
$ jm -> bStrictNullTypes = false ;
Desde la versión 5.0.0, los valores null
en las matrices generan una JsonMapper_Exception
a menos que el tipo sea anulable, por ejemplo, array[?string]
o array[string|null]
.
Para recuperar el comportamiento anterior (permitiendo valores nulos incluso cuando no se declaran así), establezca:
$ jm -> bStrictNullTypesInArrays = false ;
El método setLogger()
de JsonMapper admite todas las instancias de registrador compatibles con PSR-3.
Eventos que se registran:
Durante el desarrollo, las API cambian con frecuencia. Para recibir notificaciones sobre dichos cambios, JsonMapper se puede configurar para generar excepciones en caso de que falten datos o aún se desconozcan.
Cuando JsonMapper ve propiedades en los datos JSON que no están definidas en la clase PHP, puede permitir que genere una excepción configurando $bExceptionOnUndefinedProperty
:
$ jm = new JsonMapper ();
$ jm -> bExceptionOnUndefinedProperty = true ;
$ jm -> map (...);
También puede optar por manejar esas propiedades usted mismo configurando un invocable en $undefinedPropertyHandler
:
/**
* Handle undefined properties during JsonMapper::map()
*
* @param object $object Object that is being filled
* @param string $propName Name of the unknown JSON property
* @param mixed $jsonValue JSON value of the property
*
* @return void
*/
function setUndefinedProperty ( $ object , $ propName , $ jsonValue )
{
$ object ->{ ' UNDEF ' . $ propName } = $ jsonValue ;
}
$ jm = new JsonMapper ();
$ jm -> undefinedPropertyHandler = ' setUndefinedProperty ' ;
$ jm -> map (...);
O si deja que JsonMapper maneje el configurador por usted, puede devolver una cadena de $undefinedPropertyHandler
que se usará como nombre de propiedad.
/**
* Handle undefined properties during JsonMapper::map()
*
* @param object $object Object that is being filled
* @param string $propName Name of the unknown JSON property
* @param mixed $jsonValue JSON value of the property
*
* @return void
*/
function fixPropName ( $ object , $ propName , $ jsonValue )
{
return ucfirst ( $ propName );
}
$ jm = new JsonMapper ();
$ jm -> undefinedPropertyHandler = ' fixPropName ' ;
$ jm -> map (...);
Nota
Esto solo funciona cuando $bStrictObjectTypeChecking permanece habilitado.
Las propiedades en tus clases de PHP se pueden marcar como "requeridas" poniendo @required
en su bloque de documentos:
/**
* @var string
* @required
*/
public $ someDatum ;
Cuando los datos JSON no contienen esta propiedad, JsonMapper generará una JsonMapper_Exception
cuando se active $bExceptionOnMissingData
:
$ jm = new JsonMapper ();
$ jm -> bExceptionOnMissingData = true ;
$ jm -> map (...);
La opción $bRemoveUndefinedAttributes
hace que JsonMapper elimine propiedades del objeto final si no han estado en los datos JSON:
$ jm = new JsonMapper ();
$ jm -> bRemoveUndefinedAttributes = true ;
$ jm -> map (...);
Puede permitir el mapeo a propiedades privadas y protegidas y métodos de establecimiento estableciendo $bIgnoreVisibility
en verdadero:
$ jm = new JsonMapper ();
$ jm -> bIgnoreVisibility = true ;
$ jm -> map (...);
Cuando el tipo de una variable es una clase y los datos JSON son un tipo simple como string
, JsonMapper puede pasar este valor al constructor de la clase cuando está configurado para hacerlo:
$ jm = new JsonMapper ();
$ jm -> bStrictObjectTypeChecking = false ;
$ jm -> map (...);
Esto se puede utilizar para inicializar automáticamente objetos DateTime a partir de cadenas de fechas.
Sin embargo, deshabilitar estas comprobaciones estrictas de tipos de objetos puede generar problemas:
@required
no se completaránNota
El valor predeterminado cambió de false
a true
en la versión 5 para aumentar la seguridad.
Ahora tienes que aceptar si quieres pasar tipos simples al constructor de clases.
map()
Es posible que desees pasar datos de matriz a map()
que obtuviste llamando
json_decode ( $ jsonString , true )
De forma predeterminada, JsonMapper generará una excepción porque map()
requiere un objeto como primer parámetro. Puedes evitarlo configurando $bEnforceMapType
en false
:
$ jm = new JsonMapper ();
$ jm -> bEnforceMapType = false ;
$ jm -> map (...);
JsonMapper puede llamar a un método personalizado directamente en cada objeto una vez finalizado el mapeo:
$ jm = new JsonMapper ();
$ jm -> postMappingMethod = ' afterMapping ' ;
$ jm -> map (...);
Ahora se llama afterMapping()
en cada objeto mapeado (si la clase tiene ese método).
Puede pasar argumentos adicionales a la devolución de llamada posterior al mapeo:
$ jm = new JsonMapper ();
$ jm -> postMappingMethod = ' afterMapping ' ;
$ jm -> postMappingMethodArguments = [ 23 , ' foo ' ];
$ jm -> map (...);
Vía Composer de Packagist:
$ compositor requiere netresearch/jsonmapper
Alternativas
JsonMapper tiene licencia OSL 3.0.
JsonMapper sigue los estándares de codificación PEAR.
Christian Weiske, cweiske.de