Les petites choses marrantes en PHP: json_decode

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.

3 réflexions au sujet de « Les petites choses marrantes en PHP: json_decode »

  1. Remarque très intéressante. Cependant le problème ne vient pas de json_decode() mais du cast $array = (array) $obj;
    En effet, point de vue objet, pas de réel souci :

    $obj =  json_decode('{"185":"lol"}');
    echo $obj->{"185"}; // "lol" : pas de souci
    echo $obj->{185}; // "lol" : OK aussi
    

    Mais le vrai pb est bien-sûr d’utiliser des entiers comme noms d’attribut d’un objet.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>