jsonobject
jsonobject
est une classe PHP permettant de faciliter l'utilisation d'objets issus d'une définition JSON. L'idée vient de l'utilisation pydantic
en python et de sa capacité à analyser et valider les données json en objets.
jsonobject
J'ai dû utiliser une API de PHP, et cette API m'a renvoyé jsonobject s. J'avais donc besoin de les analyser en objets PHP que je pouvais utiliser dans l'application.
Le flux de travail est
jsonobject
pour analyser la définition JSONPrenons l'exemple JSON suivant :
{
"id" : 0 ,
"name" : " John Doe " ,
"age" : 42 ,
"emails" : [
" [email protected] " ,
" [email protected] "
],
"address" : {
"street" : " My street " ,
"number" : 42 ,
"city" : " My city " ,
"country" : " My country "
}
}
En utilisant jsonobject
, je pourrai définir mon modèle de données en utilisant les classes suivantes :
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
];
}
class Address extends jsonobject {
const ATTRIBUTES = [
' street ' => ' str ' ,
' number ' => ' int ' ,
' city ' => ' str ' ,
' country ' => ' str ' ,
];
}
Et puis ajoutez la commande suivante :
$ user = User:: fromObject ( json_decode ( $ json_text_definition ));
La classe jsonobject
effectuera l'analyse du contenu en objets, et nous pourrons utiliser ses attributs tels que définis :
echo ( $ user -> name );
Les classes définies peuvent également avoir des méthodes qui faciliteront la mise en œuvre du modèle de données de l'application. Par exemple, il serait possible de définir la classe User
comme ceci :
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
];
public function isAdult () {
return $ this -> age >= 18 ;
}
}
jsonobject
L'idée de la classe jsonobject
est de l'utiliser pour analyser les données json en objets. Ainsi, ces objets peuvent contenir d’autres méthodes qui aideront à implémenter le modèle de données de l’application.
Lorsque l'objet (ou tableau) json est analysé, son contenu est analysé de manière récursive selon les types définis dans la constante ATTRIBUTES
. Si les données ne sont pas valides, car elles ne contiennent pas les valeurs attendues, une exception est levée.
Pour utiliser jsonobject il faut sous-classer jsonobject
et définir la constante ATTRIBUTES
pour cette classe afin qu'elle définisse les attributs attendus pour les objets de cette classe, ainsi que le type de chacun.
La constante ATTRIBUTES
est un tableau associatif dans lequel les clés sont le nom de chaque attribut et les valeurs sont le type de chaque attribut .
Les types possibles peuvent être :
jsonobject
. Lors de la définition du nom des attributs, on peut ajouter un ?
à la fin du nom pour indiquer que l'attribut est facultatif. Par exemple, l' address?
dans la section cas d'utilisation est facultatif.
Chaque champ est considéré comme obligatoire et doit donc exister dans l'objet (ou le tableau) analysé. De plus, l'objet doit être du type défini (c'est-à-dire qu'il doit être correctement analysé par le type spécifique).
Tout attribut qui n'est pas facultatif est considéré comme obligatoire. Ceci est particulièrement intéressant sur deux points :
fromArray
ou fromObject
).jsonobject
Lors de la création de l'objet à partir d'une structure externe, le jsonobject
s'occupera de tous les champs obligatoires. Et si l’un d’entre eux manque, une exception sera déclenchée.
Dans l’exemple suivant, une exception sera générée car le champ obligatoire age n’est pas fourni.
class User extends jsonobject {
const ATTRIBUTES = [
" name " => " str " ,
" age " => " int " ,
];
}
( . . . )
$ user = User:: fromArray ([ " name " => " John " ]);
Lors de la conversion de l'objet en tableau ou en objet (ou lors de l'obtention de sa représentation json), un champ obligatoire obtiendra une valeur par défaut, même s'il n'est pas défini.
Donc dans l'exemple suivant
class User extends jsonobject {
const ATTRIBUTES = [
" name " => " str " ,
" age " => " int " ,
" birthDate? " => " str "
];
}
$ user = new User ();
echo (( string ) $ user );
La sortie sera
{
"name" : " " ,
"age" : 0
}
Parce que même si les attributs name et age sont obligatoires et qu'ils obtiennent leurs valeurs par défaut (c'est-à-dire 0 pour les nombres, vide pour les chaînes, les listes ou les dicts), l'attribut BirthDate n'est pas obligatoire et n'a pas encore été défini. Il n'est donc pas généré dans la sortie.
null
sur les attributs obligatoiresLe problème de la définition des valeurs sur null est particulièrement pertinent lorsqu'il s'agit de déterminer si un attribut est facultatif ou non.
On pourrait penser que si nous définissons une valeur sur null, cela signifierait supprimer la valeur et cela ne devrait donc être possible que pour les valeurs facultatives mais pas pour les valeurs obligatoires.
Dans jsonobject
, nous avons un concept différent, car définir une propriété sur null signifiera "définir une valeur sur null " et ne pas désactiver la propriété. Afin de supprimer la propriété, nous devrions utiliser la fonction unset ou quelque chose comme ça.
jsonobject
permet également de supprimer les valeurs. Pour un attribut facultatif, cela signifie supprimer la valeur et il n'aura donc aucune valeur dans une représentation matricielle ou un objet (si vous récupérez la valeur, elle sera définie sur null ).
Mais pour un attribut obligatoire, le désactiver signifiera réinitialiser sa valeur à la valeur par défaut . Cela signifie qu'il sera initialisé à la valeur par défaut du type (ie 0 pour les nombres, vide pour les listes, chaînes ou dicts, etc.) ou à sa valeur par défaut dans la constante ATTRIBUTES
.
Les jsonobject
sont également capables d'hériter des attributs de leurs classes parentes. Prenons l'exemple suivant :
class Vehicle extends jsonobject {
const ATTRIBUTES = [
" brand " => " str " ,
" color " => " str "
]
}
class Car extends Vehicle {
const ATTRIBUTES = [
" wheels " => " int "
]
}
class Boat extends Vehicle {
const ATTRIBUTES = [
" length " => " float "
]
}
Dans cet exemple, la classe Vehicle
aura uniquement les attributs brand et color , mais la classe Car
aura les attributs brand , color et wheel , tandis que la classe Boat
aura les attributs brand , color et length .
Les objets des classes enfants de jsonobject
peuvent être créés à l'aide de la méthode statique ::fromArray
ou ::fromObject
, à partir d'un objet analysé json .
Dans l'exemple précédent, si nous avons un fichier car.json avec le contenu suivant :
{
"brand" : " BMW " ,
"color" : " black "
}
Nous pouvons utiliser le code suivant pour obtenir une instance de la classe Vehicle
:
$ json = file_get_contents ( " car.json " );
$ vehicle = Vehicle:: fromArray (( array ) json_decode ( $ json , true ));
Une alternative consiste à instancier des objets comme dans l'exemple suivant
* PHP 8 et plus :
$ car = new Car (brand: " BMW " , color: " black " , wheels: 4 );
* versions PHP précédentes :
$ car = new Car ([ " brand " => " BMW " , " color " => " black " , " wheels " => 4 ]);
jsonobject
Le jsonobject
est la classe principale de cette bibliothèque. Ses méthodes sont :
__construct($data)
- Crée un nouvel objet à partir des données données__get($name)
- Renvoie la valeur de l'attribut avec le nom donné__set($name, $value)
- Définit la valeur de l'attribut portant le nom donné__isset($name)
- Renvoie vrai si l'attribut portant le nom donné est défini__unset($name)
- Annule la valeur d'un attribut facultatif (ou réinitialise la valeur d'un attribut obligatoire).toArray()
- Renvoie un tableau associatif avec les données de l'objet. Le tableau est créé de manière récursive, en visitant chacun des sous-attributs pour chaque attribut.toObject()
- Renvoie un objet avec les données de l'objet comme attributs. Le tableau est créé de manière récursive, en visitant chacun des sous-attributs pour chaque attribut.toJson()
- Renvoie une chaîne json avec la représentation de l'objet comme objet standard.::fromArray($data)
- Crée un objet, en analysant le tableau associatif donné dans les attributs définis dans la classe. Chacun des attributs est analysé de manière récursive, selon le type qui lui est défini.::fromObject($data)
- Crée un objet, en analysant l'objet donné dans les attributs définis dans la classe. Chacun des attributs est analysé de manière récursive, selon le type qui lui est défini. JsonDict
Cet objet permet de traiter un dictionnaire issu d'une définition json. La classe JsonDict
est typée de telle sorte que chacun des éléments doit appartenir à un type donné.
Les objets JsonDict
peuvent être utilisés comme des objets de type tableau (par exemple $jsonDict["key1"]) mais (au moment d'écrire ce texte) le type des éléments insérés dans le dictionnaire n'est pas vérifié. Le type est utilisé pour analyser le contenu lors de la création du dict (par exemple en utilisant la fonction statique fromArray
) ou pour vider le contenu dans un tableau ou un objet (par exemple en utilisant la fonction toArray
).
Les méthodes sont :
toArray()
toObject()
::fromArray($data)
::fromObject($data)
Ces méthodes sont interprétées de la même manière que dans le cas de jsonobject
. Et le type des éléments dans le dict peut faire référence à des types complexes qui seront pris en compte de manière récursive lors de l'analyse du contenu.
par exemple, tapez list[list[int]]
sera utilisé pour analyser [ [ 1, 2, 3], [ 4, 5, 6 ]]
JsonArray
Cet objet est très similaire à JsonDict
à l'exception du fait que les index doivent être des nombres entiers. Dans ce cas, $value["key1"]
produira une exception.
Dans ce cas, la fonction permettant d'ajouter des éléments au tableau (c'est-à-dire []
) est également implémentée.
Lors de la définition de la classe, il est possible d'initialiser les valeurs des objets nouvellement créés et des attributs facultatifs.
Il existe deux manières :
### Utilisation des propriétés de classe
Il est possible d'initialiser la valeur d'un objet en utilisant les propriétés de classe, donc si la valeur d'un attribut est définie dans la classe, elle sera copiée dans l'instance en tant qu'attribut, si elle est définie.
Par exemple
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
' sex? ' => ' str '
];
public $ sex = " not revealed " ;
}
Désormais, l'attribut sex
est initialisé à non révélé au lieu d'être nul .
La façon de le faire est de définir un tuple [ <type>, <default value> ]
pour le type de l'objet. Prenons l'exemple suivant :
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
' sex? ' => [ ' str ' , ' not revealed ' ]
];
}
L'attribut sex
est facultatif lors de la récupération des données utilisateur. En utilisant cette nouvelle définition de la classe, si sex
n'est pas défini, la valeur sera définie sur "non révélé" au lieu de null
.
Une caractéristique importante est que, si la chaîne définie comme <valeur par défaut> correspond à une méthode de l'objet, elle sera appelée lors de l'obtention de la valeur (si elle n'a pas encore été définie), et la valeur définie pour cette propriété sera être le résultat de l’appel.
Par exemple
class User extends jsonobject {
const ATTRIBUTE = [
...
' birthDay? ' => [ ' str ' , ' computeBirthDate ' ]
]
function computeBirthDate () {
$ now = new DateTime ();
$ now ->sub( DateInterval ::createFromDateString("{ $ this -> age } years"));
return $ now ->format("Y-m-d");
}
}
Dans cet exemple, si nous n'avions pas défini la propriété birthDate
mais qu'elle est récupérée, elle sera calculée en soustrayant l'âge à la date actuelle.
Si vous souhaitez analyser un objet arbitraire en jsonobject
, il est possible d'utiliser la fonction jsonobject ::parse_typed_value
. Ceci est important pour pouvoir convertir n’importe quel type en type jsonobject
.
par exemple
$ myobject = jsonobject :: parse_typed_value ( " list[str] " , [ " my " , " name " , " is " , " John " ]);
Obtiendra un objet de type JsonList<str>
.
Le comportement par défaut de cette bibliothèque est de garantir que les valeurs définies pour les attributs correspondent à leur type défini. Mais cela signifie que cela signifierait que, comme un float
n'est pas un int
, définir un float sur 0
échouera car 0
est un entier. Dans ce cas, l'utilisateur doit convertir les valeurs avant de les attribuer. Pour contrôler s'il faut vérifier si strictement le type ou non, il est possible d'utiliser la constante STRICT_TYPE_CHECKING
.
Si
STRICT_TYPE_CHECKING
est défini surTrue
, les types seront strictement vérifiés et, par exemple, attribuer9.3
à unint
déclenchera une exception. S'il est défini surFalse
, les types numériques seront convertis les uns aux autres. Ainsi, par exemple, si nous attribuons9.3
à unint
il sera automatiquement tronqué à9
.
Une autre vérification de type importante consiste à attribuer une valeur vide (c'est-à-dire ""
ou null
) à un type numérique. Dans ce cas, nous avons la constante STRICT_TYPE_CHECKING_EMPTY_ZERO
.
Si
STRICT_TYPE_CHECKING_EMPTY_ZERO
est défini surTrue
(le comportement par défaut), lors de l'attribution d'une valeur vide à un type numérique, elle sera considérée comme étant0
. c'est-à-dire qu'attribuer une chaîne vide ou une valeurnull
à un attributint
signifiera attribuer0
. Si la valeur estFalse
, la bibliothèque vérifiera les types et générera éventuellement une exception.
Désormais, JsonList
permet également d'utiliser des index négatifs, de sorte que -1
soit le dernier élément, -2
l'avant-dernier, etc.
L'objet JsonList
inclut des fonctions de tri ou de filtrage.
public function sort(callable $callback = null) : JsonList
: trie la liste en utilisant le rappel donné. Si aucun rappel n'est donné, il triera la liste en utilisant la fonction de comparaison par défaut.public function filter(callable $callback) : JsonList
: filtre la liste en utilisant le rappel donné. Le rappel doit renvoyer une valeur booléenne. Si le rappel renvoie true
, l'élément sera inclus dans la liste résultante. S'il renvoie false
, l'élément sera supprimé.