Dans un environnement de développement normalement configuré pour afficher les erreurs de type E_NOTICE mais aussi E_STRICT, on se retrouve parfois confronté à une curieuse alerte, provoquée par une séquence d'instructions qui semble pourtant anodine.
Par exemple, pour extraire l'extension d'un nom de fichier, j'écris souvent de façon machinale :
$extension = end(explode('.', $filename));
Ce qui provoque une alerte assez déroutante :
Pour comprendre ce message, il faut d'abord se rappeler que la fonction end() accepte en réalité une référence de tableau, ce qui est tout à fait compréhensible puisqu'elle va le modifier en positionnant le pointeur interne sur son dernier élément.
Ensuite [1], il faut savoir que lorsqu'une fonction retourne une valeur, une variable temporaire est créée. Généralement, on récupère cette variable temporaire en l'assignant à une autre variable déclarée explicitement, mais dans notre cas, la variable temporaire retournée par la fonction explode() est directement transmise à la fonction end() qui, bien que ce soit effectivement un Array, la refuse et provoque l'alerte.
Ce comportement tout à fait légitime ne date pas d'hier. Il a été introduit en PHP 5.0.5 afin d'éviter des corruptions mémoires. On peut certainement mieux comprendre ce risque en se souvenant de la différence significative entre les pointeurs et les références du C++.
Selon Rasmus Lerdorf, fondateur de PHP, il est recommandé d'effectuer l'opération en deux étapes, en transitant par une variable déclarée.
$split = explode('.', $filename); $extension = end($split);
Il souligne aussi à très juste titre que dans ce cas bien précis qui consiste en une opération fondamentale sur une chaîne de caractères, il est absolument injustifié de passer par un tableau pour résoudre ce problème alors que des fonctions spécifiquement dédiées aux chaînes de caractères suffisent. J'ajouterai même qu'elles seront aussi plus performantes !
$extension = substr(strrchr($filename, '.'), 1);
J'ai cependant découvert que la fonction current() ne provoque pas d'erreur avec une variable temporaire alors que son prototype signale aussi un passage par référence. On peut donc supposer, en sachant que current() ne modifie pas le pointeur interne du tableau, que le message d'erreur généré par PHP n'est pas tout à fait pertinent. Il devrait plutôt mentionner "Only variables should be updated by reference". Rasmus, si tu pouvais confirmer... ;)
Sachant cela, les fanatiques qui voudraient à tout prix s'en tirer avec une seule ligne de code peuvent toujours le faire, au prix d'une opération certainement assez coûteuse :
$extension = current(array_reverse(explode('.', $filename)));
Notes
- Je me base ici sur mes lointaines et médiocres connaissances des compilateurs C++ pour me faire une idée de la popote interne de PHP, qui doit probablement fonctionner de façon assez similaire, puisque écrit en C. A vérifier dans le code source... par un expert ;)
Liens utiles
Vos commentaires
Je vois régulièrement cette ligne de code pour récupérer l'extension d'un fichier.
Je me demande réellement pourquoi personne n'utilise la fonction spécifique, à savoir : $ext = pathinfo($filename, PATHINFO_EXTENSION); ???