Le point sur les limites du typage de PHP

{lang: 'fr'}

Les limites

PHP a ceci de particulier qu’il est est un langage de typage faible (le type des variables peut changer en cours de route), mais qu’il autorise un typage fort partiel des paramètres de fonctions pour ce qui concerne les objets et les tableaux. On pourra ainsi écrire :

function test(array $argument) {
    (...)
}

 

function test(monObjet $argument) {
    (...)
}

mais par contre il n’est pas possible de typer les paramètres de méthodes pour les types scalaires (entier, chaînes de caractères…)

function test(string $argument) {
    // qui a dit que PHP ne savait pas être drôle ?
    // Argument 1 passed to test() must be an instance of string, string given
}

Pourtant, ça semble bien souvent manquer : combien de fois vois t-on des tests de type dans un code ?

function test($argument) {
    if(!is_string($argument)) {
        throw new InvalidArgumentException("eh ! on voulait une chaîne !");
    }
}

Bref, on se retrouve avec du code pas vraiment utile (qui n’est ni métier ni applicatif), qui, bien souvent, nuit à la lecture et à la bonne compréhension des sources.

Les solutions pistes

il existe cependant des solutions, ou au moins des tentatives de solutions, pour pallier à ces inconvénients.

Patch

La première provient d’un modification du langage lui-même, sous forme d’un patch ou d’une extension. Ilia Alshanetsky propose depuis longtemps un patch pour PHP 5.3. Ce patch, complet, modifie le comportement du parseur, mais complète également Reflection.
Malheureusement, l’utilisation de ce patch nécessite de devoir patcher systématiquement PHP, avec d’autant plus de risques que le patch n’est pas officiel. Mais surtout ce patch n’est pas mis à jour, et n’est plus compatible avec les versions récentes de PHP 5.3 (ne parlons même pas de PHP 5.4 :-) )

La Standard Php Libary

Bon, c’est un idée, mais il y en a eu d’autres. Marcus Börger et David Coallier ont développé l’extension PECL SPL_Types pour insérer ce comportement dans la SPL.

Ici, pas vraiment de typage fort scalaire, mais une surcouche à utiliser :

function test(SplInt $integer){
    // (...)
}

$value = new SplInt(5);
test($value);

Ça semble marcher, mais personnellement je trouve ca peu élégant et pas vraiment optimal : quid de la compatibilité avec des librairies externes qui n’utiliseront pas les typages Spl ? Et bon, on ne type pas les scalaires ; dans notre exemple ce qui suit ne fonctionnera pas, ce qui montre en soi que cette solution n’est qu’une rustine :

assert(5 instanceof SplInt); // faux
assert(is_int( new SplInt(5) )); // faux

La rustine de la mort qui tue

Très vite, de nombreux développeurs ont eu l’idée de passer par un gestionnaire d’erreur personnalisé pour résoudre ce problème. Personnellement, je l’avais mis en place sur un framework dans une ancienne boite. À l’époque j’avais trouvé ça tout seul et ça m’avait bien amusé. Après j’avais fait des benchs et je l’avais vite retiré ;-)

L’idée est d’intercepter les erreurs, d’analyser le message de l’erreur et de voir s’il correspond pas à un problème de type. Si c’est le cas on fait nous même le contrôle « a la main », sinon on renvoie vers le gestionnaire d’erreur par défaut.

Voici une version basique :

set_error_handler(function($errno, $errstr, $errfile, $errline) {
    if(preg_match('!must be an instance of (\w*), (\w*) given!', $errstr, $matches)) {
        $matches[2] = str_replace('double','float', $matches[2]);
        return strtolower($matches[1]) == strtolower($matches[2]);
    }
});

En 6 petites lignes de code, magique : on peut désormais écrire ceci :

function example1(integer $v) {
    echo 'Cool, integer was given !'.PHP_EOL;
}
function example2(string $v) {
    echo 'Cool, string was given !'. PHP_EOL;
}
function example3(float $v) {
    echo 'Cool, float was given !';
}
function example4(boolean $v) {
    echo 'Cool, boolean was given !';
}
function example5(object $v) {
    echo 'Cool, object was given !';
}
function example6(resource $v) {
    echo 'Cool, resource was given !';
}

N’oubliez pas que c’est catastrophique côté perf :-)

Conclusion

Bref, on se retrouve avec des rustines et pas vraiment des solutions exploitables en production. Pourtant, si je comprend que le typage fort puisse gêner, je trouve que le typage des paramètres et des retours de de fonction (comme en Java par exemple) manque beaucoup, et pourrait apporter du grain dans la professionnalisation du langage.

D’ailleurs, si on observe bien, on retrouve tout de même de nombreuses RFC à ce sujet, et le sujet à été débattu à de nombreuses reprises, et par de nombreuses « figures » de PHP (Derick Rethans, Sebastian Bergmann…), on a même un moment que c’était bon. Aux dernières nouvelles (mais je dois avouer que je ne sais pas trop ce qu’il en est ) il me semble que l’introduction du typage fort des arguments des fonctions reste très largement discutée, voire contestée, et qu’alors même on l’espérait pour php 5.4, elle n’est prévue dans aucune des futures versions sur les rails.

Quel est votre avis sur la question ? Le typage fort des paramètres et des retours de fonctions vous manque t-il au quotidien ? Ou bien au contraire trouvez-vous que c’est justement la force de PHP que d’offrir une grande souplesse aux développeurs et de s’en passer ? Etes-vous déçus de ne pas avoir cette nouveauté dans PHP 5.4 ?

5 réflexions au sujet de « Le point sur les limites du typage de PHP »

  1. Jérémy

    Je demande systématiquement aux candidats que je rencontre, « quels sont les défauts selon vous de PHP », et dans 2 cas sur 3 le typage est cité.

    Personnellement, j’irais plus loin que l’assertion des arguments des fonctions. il manque vraiment à PHP une notion de typage. combien de fois on voit :

    $data = function_qui_retourne_un_objet();
    $data = $data->la_propriete_qui_m_intéresse;

    Et je ne comprend pas que le typage ne soit pas introduit et désactivable par un paramètre dans le php.ini

  2. Benji

    Moi je suis pour le typage fort. Mais il faut avouer que pour écrire de petit script, la souplesse de PHP a bien des avantages. Car si on dit typage fort, ça veut dire aussi typage du contenu des tableaux, et là, on est certainement très nombreux à ne pas le souhaiter.

    En gros il faudrait permettre de typer les arguments et le retour de la fonction, mais que cela reste un élément au choix de l’architecte (dans le php.ini par exemple, ou à la compilation de php) ou du chef de projet.

  3. Ben

    Bien d’accord pour un typage complet des paramètres et des retours de fonction. Vu l’évolution de PHP, ça aurait du faire partie de la 5.4.

    Je connais quelques devs qui voient ce manque de typage comme une vraie faiblesse de PHP. Pour certains c’est rédhibitoire.

    Je suis sûr que ça pourrait faire venir pas mal de monde si PHP évoluait dans ce sens.

    My 2 cents.

  4. mageekguy

    Ah,le vieux troll/serpent de mer est de retour…
    Il y avait bien longtemps.
    Que tous ceux qui compte sur une modification du comportement de PHP en fonction de la valeur d’un paramètre du php.ini arrête d’espérer : cela ne se fera jamais.
    Cela rendrait le code non « transportable » d’une configuration à une autre et même si ce n’était pas le cas, cela pourrait avoir des effets de bord très pernicieux.
    Pour avoir suivi le débat pendant assez longtemps, 3 écoles s’affrontent sur ce point.
    Il y a ceux qui disent que c’est complètement inutile car le typage dynamique existe pour résoudre le problème et que ceux qui recours aux artifices « is_string()/is_int()/is_etc() » sont des mauvais développeurs PHP qui n’ont rien compris au langage (ne vous sentez surtout pas offensé par mon propos, je ne fais que relater une opinion tierce).
    Et il y a ceux qui sont clairement pour un typage fort.
    Cependant, au sein de ces derniers, deux courants s’affrontent.
    Il y a ceux qui prône juste un contrôle du type de l’argument qui générera une erreur à l’exécution.
    Et il y a ceux qui veulent qu’une conversion automatique vers le type demandé soit effectuée.
    J’ajouterais que parmi le premier « courant de pensée », ils y a ceux qui veulent une exception à la place d’une erreur, ou qui veulent une E_STRICT à la place d’un E_WARNING ou d’une E_FATAL, j’en passe et des meilleures, sans encore de ceux qui veulent typer le contenu des tableaux et des propriétés.
    De plus, en fonction de la solution retenue, l’implémentation technique peut avoir un impact plus ou moins important sur les performances.
    Bref, le problème n’est pas évident, les solutions techniques encore moins et nous ne sommes donc pas prêt d’avoir un typage fort dans PHP vu que l’obtention d’un consensus sur ce point parmi les développeurs est loin d’être d’actualité.
    Donc, en attendant que tous ces gens se mettent d’accord, il a été décidé de ne rien faire.
    Dans l’intervalle, nous avons une solution bâtarde qui a au moins le mérite d’exister et d’être fonctionnelle (mais qui je le reconnais, surtout pour un ancien développeur C/C++, fait rêver de plus).

    1. jeff Auteur de l’article

      @mageekguy: Très bonne synthèse, merci d’avoir complété ce billet :-)

      Mon objectif n’est pas de lancer un troll, juste d’avoir un ressenti des options des développeurs à ce sujet ;-) . Perso moi ça me frustre bien souvent de voir du code « inutile » dans des sources… Après je comprend que les points de vues puissent différer.

      @Benji, @Ben effectivement, c’est souvent une critique que j’entends. Ceci dit je crois que malgré tous ces reproches, de plus en plus de gros projets sont fait en PHP. C’est juste une impression ?

Les commentaires sont fermés.