De la subtilité de générer du JSON en PHP

J’ai récemment été confronté à un bug dans une application JavaScript au boulot. J’ai mis un certain temps à comprendre car je ne connaissais pas la subtilité dont je vais vous parler. Ne vous attendez pas à des révélations fracassantes ni à des démissions en chaînes, il s’agit d’un tout petit point qui mérite l’attention des développeurs et qui relève autant de la logique et du bon sens que de la connaissance des langages incriminés !

J’utilise un script PHP pour récupérer des données en base de données qui sont ensuite formatées en JSON avant d’être transmises à l’application JavaScript (JS). Il s’agissait d’une collection de couleurs (avec des infos du genre identifiant, code de la couleur et nom de public de la couleur).

Tout fonctionnait bien jusqu’à très récemment (l’application JS permet de dessiner en pixel art) et j’ai donc cherché pourquoi une des fonctionnalités (l’importation d’une image et sa transformation en pixel) ne marchait plus. Après un bon moment de debugging dans le JS, j’ai fini par découvrir que c’était lorsque l’application bouclait sur la collection de couleurs que les problèmes survenaient:

for(var i = 0, acl = availableColors.length; i < acl; i++)

L’instruction « availableColors.length » renvoie  » undefined  » alors que availableColors me montre une collection d’objets JSON. Oui mais non, pas tout à fait. Comme me le fait remarquer un collègue, firebug indique un objet contenant les objets couleurs et non pas un tableau. Or, l’appel à « .length » ne fonctionne que sur les tableaux. C’est l’une des choses sur lesquelles il faut être attentif lorsqu’on travaille sur du JSON généré par PHP. Mais pourquoi diable ?

La réponse se trouvait dans la méthode PHP qui récupère les données dans une BDD : j’ai récemment modifié l’array PHP de sortie en le transformant en array associatif (ironiquement, pour corriger un bug. Merci l’absence de tests ahah). Ce même tableau transformé en JSON par « json_encode » lors de la transmission à la vue. Un petit tour sur la page de la documentation de json_encode m’a permis de réaliser que les array associatifs sont toujours transformés en objet JSON.

Il m’a suffit d’écrire une méthode qui se charge de générer le JSON qui sera envoyé au client.

     /**
      * Returns a JSON string ready to be used by the client
      *
      */
     public static function formatAvailableColorsForClient(array $availableColors)
     {
         return json_encode(array_values($availableColors));
     }

Pour info, la fonction array_values permet de réindexer un tableau.

Et voilà !