Prend les données récupérées à partir d'un service Web JSON et les convertit en objets et tableaux imbriqués - en utilisant vos propres classes de modèle.
À partir d'un objet de base, il mappe les données JSON sur les propriétés de classe, les convertissant en types ou objets simples corrects.
C'est un peu comme le mappage de paramètres SOAP natif SoapClient
de PHP vous offre, mais pour JSON. Il ne repose sur aucun schéma, uniquement sur les définitions de vos classes PHP.
La détection de type fonctionne en analysant les déclarations de type et les annotations @var
docblock des propriétés de classe, ainsi que les indications de type dans les méthodes setter.
Vous n'êtes pas obligé de modifier vos classes de modèle en ajoutant du code spécifique JSON ; il fonctionne automatiquement en analysant les docblocks déjà existants.
Cette bibliothèque n'a aucune dépendance.
Mots clés : désérialisation, hydratation
Contenu
map()
Les classes modèles doivent être écrites à la main
Étant donné que JsonMapper ne s'appuie sur aucune information de schéma (par exemple provenant de json-schema), les classes de modèle ne peuvent pas être générées automatiquement.
netresearch/jsonmapper
avec composerJsonMapper
map
ou mapArray
, en fonction de vos donnéesMapper un objet normal :
<?php
require ' autoload.php ' ;
$ mapper = new JsonMapper ();
$ contactObject = $ mapper -> map ( $ jsonContact , new Contact ());
// or as classname
$ contactObject = $ mapper -> map ( $ jsonContact , Contact::class);
Mappez un tableau d'objets :
<?php
require ' autoload.php ' ;
$ mapper = new JsonMapper ();
$ contactsArray = $ mapper -> mapArray (
$ jsonContacts , array (), ' Contact '
);
Au lieu de array()
vous pouvez également utiliser ArrayObject
et des classes dérivées, ainsi que des classes implémentant ArrayAccess
.
JSON à partir d'un service Web de carnet d'adresses :
{
"name" : "Sheldon Cooper" ,
"address" : {
"street" : "2311 N. Los Robles Avenue" ,
"city" : "Pasadena"
}
}
Votre classe Contact
locale :
<?php
class Contact
{
/**
* Full name
*/
public string $ name ;
public ? Address $ address ;
}
Votre classe Address
locale :
<?php
class Address
{
public $ street ;
public $ city ;
public function getGeoCoords ()
{
//do something with $street and $city
}
}
Votre code de candidature :
<?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
utilise plusieurs sources pour détecter le type correct d'une propriété dans l'ordre suivant :
Méthode Setter ( set
+ ucwords($propertyname)
)
Les traits de soulignement « _
» et les tirets « -
» mettent la lettre suivante en majuscule. La propriété foo_bar-baz
mène à la méthode setter setFooBarBaz
.
S'il a un indice de type dans la signature de la méthode, alors son type est utilisé :
fonction publique setPerson(Contact $person) {...}
Le docblock de la méthode est inspecté pour les annotations @param $type
:
/** * @param Contact $person Contact principal pour cette application */ fonction publique setPerson($personne) {...}
Si aucun type n'a pu être détecté, la valeur JSON simple est transmise à la méthode setter.
Types de propriétés de classe (depuis PHP 7.4) :
personne à contacter publique ;
Types de promotion de propriétés constructeur (depuis PHP 8.0) :
fonction publique __construct (Contact protégé $ personne) {}
@var $type
docblock annotation des propriétés de classe :
/** * @var monapplicationmodèleContact */ personne publique ;
La propriété doit être publique pour être utilisée directement. Vous pouvez également utiliser $bIgnoreVisibility pour utiliser des propriétés protégées et privées.
Si aucun type n’a pu être détecté, la propriété obtient l’ensemble de valeurs JSON simple.
Si une propriété est introuvable, JsonMapper essaie de la trouver sans tenir compte de la casse. Une propriété JSON isempty
serait alors mappée à une propriété PHP isEmpty
.
Note
Vous devez fournir l'espace de noms complet pour que le type fonctionne. Les noms de classes relatifs sont évalués dans le contexte de l'espace de noms des classes actuelles, sans respecter les importations qui peuvent être présentes.
PHP ne fournit pas les importations via Reflection ; le texte du commentaire contient uniquement le texte littéral du type. Pour des raisons de performances, JsonMapper n'analyse pas lui-même le code source pour détecter et développer les importations.
Types simples
string
bool
, boolean
int
, integer
double
, float
array
object
mixed
Noms de classe, avec et sans espaces de noms
Contact
- une exception sera levée si la valeur JSON est null
Tableaux de types simples et de noms de classes :
int[]
Contact[]
Tableaux multidimensionnels :
int[][]
TreeDeePixel[][][]
ArrayObjects de types simples et noms de classe :
ContactList[Contact]
NumberList[int]
Énumérations sauvegardées, avec et sans espaces de noms
Suit:string|Suit:int
- une exception sera levée si la valeur JSON n'est pas présente dans l'énumération
Types nullables :
int|null
ou ?int
- sera null
si la valeur dans JSON est null
, sinon ce sera un entierContact|null
ou ?Contact
- sera null
si la valeur dans JSON est null
, sinon ce sera un objet de type Contact
Les ArrayObjects et les classes d'extension sont traités comme des tableaux.
Les variables sans type ou avec un type mixed
obtiendront la valeur JSON définie directement sans aucune conversion.
Voir la documentation des types de phpdoc pour plus d'informations.
Note
Cette fonctionnalité est désactivée par défaut pour des raisons de sécurité depuis la version 5. Voir $bStrictObjectTypeChecking pour plus de détails.
Lorsqu'un objet doit être créé mais que le JSON contient uniquement un type simple (par exemple string, float, boolean), cette valeur est transmise au constructeur des classes. Exemple:
Code PHP :
public DateTime $ date ;
JSON :
{ "date" : "2014-05-15" }
Cela entraînera l'appel de new DateTime('2014-05-15')
.
Lorsque les variables sont définies en tant qu'objets de classes abstraites ou d'interfaces, JsonMapper essaie normalement de les instancier directement et plante.
À l'aide de la propriété $classMap
de JsonMapper, vous pouvez spécifier quelles classes doivent être instanciées à la place :
$ jm = new JsonMapper ();
$ jm -> classMap [ ' Foo ' ] = ' Bar ' ;
$ jm -> map (...);
Cela créerait des objets de type Bar
lorsqu'une variable est définie comme étant de type Foo
.
Il est également possible d'utiliser un callable dans le cas où la classe d'implémentation réelle doit être déterminée dynamiquement (par exemple dans le cas d'une union). La classe mappée (« Foo » dans l'exemple ci-dessous) et les données Json sont transmises en tant que paramètres dans l'appel.
$ 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 lève une exception lorsqu'une propriété JSON est null
, sauf si la propriété de classe PHP a un type nullable - par exemple Contact|null
ou ?Contact
.
Si votre API contient de nombreux champs pouvant être null
et que vous ne souhaitez pas rendre toutes vos définitions de type nullables, définissez :
$ jm -> bStrictNullTypes = false ;
Depuis la version 5.0.0, les valeurs null
dans les tableaux conduisent à une JsonMapper_Exception
sauf si le type est nullable - par exemple array[?string]
ou array[string|null]
.
Pour récupérer le comportement précédent (autorisant les valeurs nulles même lorsqu'elles ne sont pas déclarées ainsi), définissez :
$ jm -> bStrictNullTypesInArrays = false ;
La méthode setLogger()
de JsonMapper prend en charge toutes les instances d'enregistreur compatibles PSR-3.
Événements enregistrés :
Pendant le développement, les API changent souvent. Pour être informé de ces changements, JsonMapper peut être configuré pour lever des exceptions en cas de données manquantes ou encore inconnues.
Lorsque JsonMapper voit des propriétés dans les données JSON qui ne sont pas définies dans la classe PHP, vous pouvez le laisser lever une exception en définissant $bExceptionOnUndefinedProperty
:
$ jm = new JsonMapper ();
$ jm -> bExceptionOnUndefinedProperty = true ;
$ jm -> map (...);
Vous pouvez également choisir de gérer ces propriétés vous-même en définissant un appelable sur $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 (...);
Ou si vous laissez JsonMapper gérer le setter pour vous, vous pouvez renvoyer une chaîne de $undefinedPropertyHandler
qui sera utilisée comme nom de propriété.
/**
* 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 (...);
Note
Cela ne fonctionne que lorsque $bStrictObjectTypeChecking reste activé.
Les propriétés de vos classes PHP peuvent être marquées comme « obligatoires » en mettant @required
dans leur docblock :
/**
* @var string
* @required
*/
public $ someDatum ;
Lorsque les données JSON ne contiennent pas cette propriété, JsonMapper lèvera une JsonMapper_Exception
lorsque $bExceptionOnMissingData
est activé :
$ jm = new JsonMapper ();
$ jm -> bExceptionOnMissingData = true ;
$ jm -> map (...);
L'option $bRemoveUndefinedAttributes
oblige JsonMapper à supprimer les propriétés de l'objet final si elles ne figurent pas dans les données JSON :
$ jm = new JsonMapper ();
$ jm -> bRemoveUndefinedAttributes = true ;
$ jm -> map (...);
Vous pouvez autoriser le mappage vers des propriétés privées et protégées et des méthodes de définition en définissant $bIgnoreVisibility
sur true :
$ jm = new JsonMapper ();
$ jm -> bIgnoreVisibility = true ;
$ jm -> map (...);
Lorsque le type d'une variable est une classe et que les données JSON sont un type simple comme string
, JsonMapper peut transmettre cette valeur au constructeur de la classe lorsqu'il est configuré pour le faire :
$ jm = new JsonMapper ();
$ jm -> bStrictObjectTypeChecking = false ;
$ jm -> map (...);
Cela peut être utilisé pour initialiser automatiquement les objets DateTime à partir de chaînes de date.
La désactivation de ces vérifications strictes du type d'objet peut cependant entraîner des problèmes :
@required
ne seront pas rempliesNote
La valeur par défaut est passée de false
à true
dans la version 5 pour augmenter la sécurité.
Vous devez maintenant vous inscrire si vous souhaitez transmettre des types simples au constructeur de classe.
map()
Vous souhaiterez peut-être transmettre les données du tableau dans map()
que vous avez obtenues en appelant
json_decode ( $ jsonString , true )
Par défaut, JsonMapper lèvera une exception car map()
nécessite un objet comme premier paramètre. Vous pouvez contourner cela en définissant $bEnforceMapType
sur false
:
$ jm = new JsonMapper ();
$ jm -> bEnforceMapType = false ;
$ jm -> map (...);
JsonMapper est capable d'appeler une méthode personnalisée directement sur chaque objet une fois le mappage terminé :
$ jm = new JsonMapper ();
$ jm -> postMappingMethod = ' afterMapping ' ;
$ jm -> map (...);
Désormais, afterMapping()
est appelé sur chaque objet mappé (si la classe possède cette méthode).
Vous pouvez transmettre des arguments supplémentaires au rappel post-mapping :
$ jm = new JsonMapper ();
$ jm -> postMappingMethod = ' afterMapping ' ;
$ jm -> postMappingMethodArguments = [ 23 , ' foo ' ];
$ jm -> map (...);
Via Composer de Packagist :
$ composer nécessite netresearch/jsonmapper
Alternatives
JsonMapper est sous licence OSL 3.0.
JsonMapper suit les normes de codage PEAR.
Christian Weiske, cweiske.de