PHP n'est pas faiblement typé !
On peut souvent lire que PHP est un langage faiblement typé, et je dois l’avouer, c’est toujours une remarque qui me provoque.
Comme si c’était une attaque personnelle, alors que je ne suis pas PHP !
Parfois, des choses nous irritent sans raison.
L’idée de ce billet m’est venue après un échange LinkedIn (vous me direz…) sur le fait que PHP est un langage faiblement typé.
Chose avec laquelle je ne suis pas d’accord, mais force est de reconnaître que c’est un avis peu partagé dans la communauté, pour plusieurs raisons :
- Tout le monde s’en fout au fond, et c’est une excellente raison.
- Une compréhension différente du typage de PHP.
Alors reprenons un peu ce qu’est le typage faible et ce qu’est PHP !
(Billet d’opinion en approche !)
Le typage faible et le typage fort
Il n’y a pas vraiment de définition précise du terme typage faible/typage fort, du moins aucune qui fasse vraiment consensus.
En général, on retrouve suivant les époques les définitions suivantes (l’ordre n’a pas d’importance) :
- La sécurité des types (type safety) : c’est la propriété la plus souvent associée au “typage fort” : un langage est type-safe s’il empêche les erreurs à l’exécution dues à des incompatibilités de types (par exemple, essayer d’additionner un int et une string).
- Conversions implicites (coercion) : un langage “faiblement typé” autorise généralement plus de conversions automatiques et implicites entre types (ex : une chaîne de caractères utilisée comme un nombre,
'10'
peut devenir 10). Un langage dit “fortement typé” exigerait des conversions explicites. - Vérification statique vs. dynamique : cette distinction porte sur le moment où les types sont vérifiés.
- Typage statique : les types sont vérifiés à la compilation (ex : Java, C#, C++).
- Typage dynamique : les types sont vérifiés à l’exécution (ex : Python, Ruby, JavaScript).
- Sécurité mémoire (memory safety, Rust m’entends-tu ?) : liée à la capacité d’un langage à prévenir les accès mémoire non valides (comme le C peut le faire). On ne parlera pas de ce point, puisqu’il est caduque en PHP.
Les langages dynamiquement typés (comme Python) peuvent être “fortement typés” dans le sens de la sécurité des types, car ils évitent les erreurs d’incompatibilité à l’exécution, même sans vérification statique (via le “duck typing”, une sorte de typage structurel).
Et donc pour PHP, ça donne quoi ?
Ce que PHP dit de lui-même
Revenons un peu sur la définition du typage de PHP :
PHP uses a nominal type system with a strong behavioral subtyping relation. The subtyping relation is checked at compile time whereas the verification of types is dynamically checked at run time.
PHP’s type system supports various atomic types that can be composed together to create more complex types. Some of these types can be written as type declarations.
Source: https://www.php.net/manual/en/language.types.type-system.php
Oui, PHP ne se décrit pas explicitement comme faiblement typé (on reviendra sur ce point).
Ce que ça veut dire
Reprenons doucement ce que cela signifie :
PHP uses a nominal type system
: le système de type de PHP est nominal, c’est-à-dire que l’égalité des types est basée sur leur nom plutôt que leur structure. Si les types ne portent pas le même nom mais possèdent la même structure, ils ne sont pas identiques.a strong behavioral subtyping relation
: le sous-typage en PHP est fort, c’est-à-dire que les types dérivés doivent respecter le comportement de leur type parent. C’est très ancré dans la POO.The subtyping relation is checked at compile time whereas the verification of types is dynamically checked at run time
: les relations de sous-typage sont vérifiées à la compilation, tandis que la vérification des types se fait dynamiquement à l’exécution. On a donc un langage dynamique qui n’est pas totalement dynamique. Ici, la compilation sous-entend l’étape qui convertit le code en instructions à la VM Zend.
Le typage faible dans tout ça
Un typage nominal est par définition strict, donc fort ? PHP précise qu’il utilise un sous-typage strong
, autrement dit strict.
Si j’ai un type Animal
qui a 2 sous-types Chien
et Chat
(ils héritent d’Animal
par exemple), alors les deux derniers sont aussi du type Animal
.
De la POO basique jusqu’à présent.
On ne peut pas faire passer un Chien
pour un Chat
, même s’ils ont tous les deux 4 pattes, mais on peut les faire passer pour un Animal
.
Comme PHP fait une vérification nominale, Chien
sera mécaniquement différent de Chat
.
Pour moi, ça sonne comme de la sécurité des types (type safety) du point (1), non ? Ouais…
Le jonglage de type (type juggling)
PHP fait quelque chose de très particulier au niveau de certains types : du type juggling
.
Quand un argument d’une fonction demande un type précis et que ce que vous lui donnez n’est pas le type attendu mais un autre compatible, alors il va faire la conversion pour vous…
$first = '10';
$second = 10;
$add = fn (int $a, int $b) => $a + $b;
echo $add($first, $second); // output: 20
Tester ici : https://3v4l.org/6CA74#vnull
Qu’est-ce que PHP fait ici ?
Il comprend que l’on souhaite faire une addition de deux entiers, mais on fournit une string dans un des deux cas. Il se trouve que le type string est compatible dans certains cas avec un entier, donc il parse cette string, et si un entier est trouvé, il va fournir cet argument à la place de la string.
Est-ce que le type de $first
est changé ? Non ! Cela reste une string ! C’est la valeur injectée qui est transformée.
PHP fait en quelque sorte cela :
$add((int) $first, $second);
(Ce n’est pas factuellement vrai, c’est pour l’exemple)
Pour faire cela, il faut trois choses :
- Connaître le type d’origine, PHP a donc toujours connaissance des types des valeurs.
- Connaître le type de destination
- Pouvoir convertir l’une dans le type de l’autre
C’est fort, non ? Donc PHP garde toujours les types en mémoire, et s’arrange pour nous faciliter la vie quand cela est possible avec la conversion qui va bien. Le jonglage de type est documenté ici si vous souhaitez en savoir plus : https://www.php.net/manual/en/language.types.type-juggling.php.
PHP est donc un langage qui a une sécurité de type, mais pas tout le temps.
Un Chien
n’est pas un Chat
, pourtant les deux sont des Animal
, et puis une string n’est pas un entier, mais je peux convertir le premier dans le second.
Une instruction à le rescousse
On peut empêcher PHP de faire du jonglage de type, avec une simple instruction en début de fichier :
declare(strict_types=1);
Ce faisant, PHP ne fera plus aucune conversion de type implicite. On relâche donc la seule ombre qui nous faisait pencher vers du typage faible. PHP est donc fortement typé non ? non ?…
Du coup PHP, il est quoi ?
Alors PHP, typage fort ou faible ? Ça dépend de quel type on parle, mais il n’est jamais dupe ! Comme toujours, PHP est un langage qui est un entre-deux.
Il est :
- Nominal et fort (strict) sur les types objets.
- Par défaut permissif (faible) sur les types primitifs compatibles.
- Dynamiquement typé à l’exécution, mais avec vérification statique à la compilation des sous-types.
- Toujours conscient des types réels des références.
PHP n’est donc ni faiblement ni fortement typé, mais se situe quelque part entre les deux selon le contexte, les types manipulés et les options d’exécution. Aussi selon votre définition.
Il n’y a pas de bonne réponse puisque le critère faible/fort
n’est pas bien défini !
Mais c’est bien ou pas, ce jonglage de type ?
C’est toute la question en effet ! Bien pour qui ? Bien dans quel contexte ?
Personnellement, je trouve cela affreux, mais quand je débutais la programmation, j’adorais cette fonctionnalité. Il y a quelques semaines, je me souviens d’une discussion enflammée sur l’usage de PHP pour développer des CLI. J’argumentais que le langage n’est pas adapté parce qu’interprété ; mon interlocuteur (dont j’estime fort les prises de position) argumentait au contraire que si, PHP étant un langage simple et accessible pour tous. Je crois qu’il capture bien l’essence même de PHP : simple et accessible, on peut construire et avancer, sans se soucier de trop de choses. Il fait le boulot, il le fait suffisamment bien.
C’est aussi sa plus grande faiblesse pour de gros projets, avec les centaines de footguns à la ligne.
Cette question est d’ailleurs le sujet d’une RFC actuelle, sur sa partie la plus footgun, la conversion implicite des bool
.
Références
- Documentation officielle du système de types PHP
- Documentation sur le Type Juggling