Contents
Aujourd’hui est venu le temps d’initier notre série Les petites choses marrantes en PHP, consacrées aux petites choses marrantes en PHP, avec quelques exemples de petites choses marrantes en matière d’accès impossibles aux attributs d’objets et clés de tableaux lorsqu’on utilise la fonction json_decode.
Mais attention, que les choses soient bien claires: il ne s’agit pas de troll! Juste de faire gaffe…
Accès aux attributs impossibles
Nous savons tous qu’en PHP, tout logiquement, le nom des attributs d’une classe doit correspondre à une liste de caractères permis, excluant notamment tout attribut constitué d’une chaîne de caractère vide, ou même d’un nombre.
Valeurs numériques
Il n’empêche qu’il est possible de définir dynamiquement des attributs numériques et d’y avoir accès, via la notation entre accolades.
1 2 3 | $stdObject->{185} = 'lol'; //on note au passage que PHP n'exige pas d'initialiser d'objet de type StdClass, mais que cela n'est pas très propre. var_dump($stdObject); //object(stdClass)#1 (1) { ["185"] => string(3) "lol" } var_dump($stdObject->{185}); //string(3) "lol" |
De même, la conversion d’un Json peut entraîner des résultats similaires.
1 2 3 | $json = json_decode('{"185":"lol"}'); var_dump($json); //object(stdClass)#1 (1) { ["185"] => string(3) "lol" } var_dump($json->{185}); //string(3) "lol" |
Jusque là, tout semble logique, si on accepte qu’on puisse créer et accéder à des attributs dont le nom n’est pas qualifié de manière standard et que seul l’accès entre accolades est utilisable.
Valeurs vides
Par contre, la gestion des attributs vides est plus capricieuse: impossible de déclarer ou de lire un attribut vide via la notation entre accolades.
1 | $stdObject->{''} = 'lol'; //Fatal error: Cannot access empty property |
Pourtant, via un Json, il est possible de créer un attribut vide, et d’y avoir accès via l’attribut _empty_ qui apparaît un peu par enchantement.
1 2 3 | $json = json_decode('{"":"lol"}'); var_dump($json); //object(stdClass)#1 (1) { ["_empty_"] => string(3) "lol" } var_dump($json->_empty_); //string(3) "lol" |
Mais bien sûr, si _empty_ permet de lire un attribut vide, il ne permet pas pour autant de le définir.
1 2 | $stdObject->{'_empty_'} = 'lol'; var_dump($stdObject); //object(stdClass)#1 (1) { ["_empty_"] => string(3) "lol" } |
Donc, ces deux attributs, « _empty_ » et « », s’écrasent lors de la conversion d’un Json.
1 | var_dump(json_decode('{"":"lol", "_empty_":"kikou"}')); //object(stdClass)#1 (1) { ["_empty_"] => string(5) "kikou" } |
Mais, si on avait choisi le mode de conversion vers un tableau, rien de tout cela ne serait arrivé.
1 | var_dump(json_decode('{"":"lol", "_empty_":"kikou"}', true)); //array(2) { [""] => string(3) "lol", ["_empty_"] => string(5) "kikou" } |
Marrant, non?
Accès aux clés impossibles
Valeurs numériques
Nous savons tous que PHP convertit une clé numérique d’un tableau en un entier.
1 2 | $array = array("185" => "lol"); var_dump($array); //array(1) { [185] => string(3) "lol" } // => la clé est de type int |
Ainsi, on peut accéder à cette valeur via une clé de type int ou string, indifféremment.
1 2 | var_dump($array[185]); //string(3) "lol" var_dump($array['185']); //string(3) "lol" |
Pourtant, si on convertit un objet disposant d’un attribut numérique, celui-ci n’est pas casté en entier comme clé de tableau.
1 2 | $array = (array) json_decode('{"185":"lol"}'); var_dump($array); //array(1) { ["185"] => string(3) "lol" } // => la clé est de type string |
Dès lors, on ne peut accéder à cette valeur via une clé de type int ou string. En effet, de ce côté, PHP continue à convertir la clé numérique, recherchant ainsi une clé qui n’existe pas.
1 2 | var_dump($array[185]); //NULL var_dump($array['185']); //NULL |
Pourtant, si on boucle sur le tableau, nous constatons que la clé est bien présente dans le tableau.
1 2 3 | foreach($array as $key=>$value){ var_dump($key); //string(3) "185" } |
La boucle est le seul moyen d’accéder à cette valeur cachée.
Mais, si on avait choisi le mode de conversion vers un tableau, rien de tout cela ne serait arrivé.
1 | var_dump(json_decode('{"185":"lol"}', true)); //array(1) { [185] => string(3) "lol" } // => la clé est de type int |
Marrant, non?
Conclusion
Mieux vaut utiliser json_decode en mode de conversion vers un tableau, en passant true comme deuxième argument.
Très instructif ! Merci !