Sommaire
Bon si tu es dev aguerri en PHP, tu peux probablement passer ton chemin car tu sais forcément à quoi sert cette commande mystérieuse que l'on peut trouver parfois au début d'un script PHP.
<?php
declare(strict_types=1);
// ...
Wait ?! C'est bien une lueur de doute dans tes yeux que je viens de voir passer ?
Ici pas de moqueries, pas de jugement, il est parfaitement possible d'être très expérimenté mais ne pas tout connaître. On est tous là pour apprendre, non ?
declare(strict_types=1)
?Bon avant de rentrer dans le vif du sujet faisons, si tu le veux bien, un peu d'archéologie. Remontons d'environ 10 ans dans l'histoire de PHP.
declare(strict_types=1)
est apparu avec PHP 7.0 qui est sortie le 3 décembre 2015.
Et si on souhaite être précis, cette syntaxe découle de la PHP RFC: Scalar Type Declarations de février 2015.
En voici le summary original et la traduction juste en dessous :
This RFC proposes the addition of four new type declarations for scalar types: int, float, string and bool. These type declarations would behave identically to the existing mechanisms that built-in PHP functions use.
This RFC further proposes the addition of a new optional per-file directive, declare(strict_types=1);, which makes all function calls and return statements within a file have “strict” type-checking for scalar type declarations, including for extension and built-in PHP functions. In addition, calls to extension and built-in PHP functions with this directive produce an E_RECOVERABLE_ERROR on parameter parsing failure, bringing them into line with existing userland type declarations.
With these two features, it is hoped that more correct and self-documenting PHP programs can be written.
Traduction française :
Cette RFC propose l'ajout de quatre nouvelles déclarations de type pour les types scalaires : int, float, string et bool. Ces déclarations de types se comporteraient de manière identique aux mécanismes existants que les fonctions PHP intégrées utilisent.
Cette RFC propose également l'ajout d'une nouvelle directive optionnelle par fichier, declare(strict_types=1) ;, qui fait que tous les appels de fonction et les déclarations de retour dans un fichier ont un contrôle de type "strict" pour les déclarations de type scalaire, y compris pour les fonctions PHP intégrées et d'extension. De plus, les appels aux extensions et aux fonctions PHP intégrées avec cette directive produisent un E_RECOVERABLE_ERROR sur l'échec de l'analyse des paramètres, ce qui les met en ligne avec les déclarations de types existantes dans le userland.
Avec ces deux fonctionnalités, nous espérons que des programmes PHP plus corrects et auto-documentés pourront être écrits.
On comprends ainsi que strict_types
ne s'appliquent qu'aux types scalaires : int, float, string et bool.
declare(strict_types=1)
?Comme on a pu le voir dans la RFC ci-dessus, le rôle de cette syntaxe est de vérifier que chaque variable corresponds bien à son type : une variable int doit contenir un entier, une string doit contenir une chaîne de caractère etc.
Cela vise également à empêcher certains bugs compliqués à résoudre de se produire.
Cette syntaxe apporte aussi une meilleure lisibilité et compréhension du script, car il n'est plus nécessaire de faire des plans sur la comète pour savoir quel type de données telle ou telle variable va contenir.
Précision utile : la seule exception est qu'une variable de type float
peut contenir un entier :
<?php
declare(strict_types=1);
function addNumber(float $var1, float $var2): float
{
return $var1 + $var2;
}
echo addNumber(4, 3.25);
// return 7.25
Cela se retrouve d'ailleurs précisé dans la RFC et cela a été évidemment discuté par la team en charge de PHP à l'époque.
La première règle est que l'instruction declare(strict_types=1)
doit apparaître en première ligne de ton fichier PHP juste après les balises d'ouverture.
Il faut savoir que les conséquences de l'utilisation de cette syntaxe ne s'applique que sur le fichier PHP en cours.
Il n'est pas possible d'appliquer cette instruction sur l'ensemble de ta codebase PHP. Cela se fait vraiment fichier par fichier.
Concrètement, voici ce que tu dois mettre au début de chaque fichier où tu souhaites mettre en place le contrôle de type strict :
<?php
declare(strict_types=1);
// Put here the rest of your script...
Et voilà, à présent tu sais comment mettre en place cette instruction dans tes scripts. Easy, peasy non ?
Il est possible de s'assurer que tous tes scripts PHP d'un namespace donné utilisent bien cette déclaration.
Comment ?
En utilisant PestPHP et les tests d'architectures :
arch('app')
->expect('App')
->toUseStrictTypes();
Voir la documentation de PestPHP à ce sujet.
Par défaut PHP te permet d'écrire ceci :
<?php
function addNumber(int $var1, int $var2): int
{
return $var1 + $var2;
}
echo addNumber(4, "3");
// return 7
En effet, comme le mentionne la documentation, PHP est un langage à typage dynamique, ce qui signifie que par défaut, il n'est pas nécessaire de spécifier le type d'une variable, car il est déterminé à l'exécution.
À présent, ajoutons notre directive declare(strict_types=1)
:
<?php
declare(strict_types=1);
function addNumber(int $var1, int $var2): int
{
return $var1 + $var2;
}
echo addNumber(4, "3");
// return :
// Fatal error: Uncaught TypeError: addNumber(): Argument #2 ($var2) must be of type int, string given, called in /in/iUhCc on line 9 and defined in /in/iUhCc:4
// Stack trace:
// #0 /in/iUhCc(9): addNumber(4, '3')
// #1 {main}
// thrown in /in/iUhCc on line 4
//
// Process exited with code 255.
Évidemment sur un exemple aussi trivial l'intérêt peut sembler faible voir inexistant.
Mais dans des développements plus complexe, t'assurer que chaque variable est du type pour lequel elle est prévue peut littéralement te sauver de plusieurs heures de débogage et préserver par la même occasion ta masse capillaire.
declare(strict_types=1)
peut il m'aider dans mon quotidien de dev PHP ?Cette instruction peut te permettre :
Il est important de parler également des limitations de cette déclaration.
Si dans ton script principal qui n'est pas "strict typé" (index.php), tu fais appel à un autre script qui lui est "strict typé" (functions.php), tu pourras remarquer que le typage strict ne s'appliquera pas.
Fichier 'functions.php'
<?php
declare(strict_types=1);
function addNumber(float $var1, float $var2): float
{
return $var1 + $var2;
}
Fichier 'index.php'
<?php
// index.php file
// No strict declarations
include('functions.php');
$sum = addNumber("3", 2);
echo "Sum : $sum";
// return Sum : 5
Comme tu peux le voir le script va retourner :
Sum : 5
sans tenir compte du fait que "3" n'est ni un float, ni un int mais une string.
Pour que le strict_types
fonctionne, il aurait fallu ajouter la déclaration declare(strict_types=1)
au fichier index.php.
Tu pourras consulter cela sur le notebook qui me sert de bac à sable.
Je ne suis personne pour te dire ce que tu dois faire et ne pas faire.
Chaque dev est libre d'utiliser ou non cette instruction. Tu peux aussi bien te dire :
Je laisse PHP gérer tout cela à ma place avec le typage dynamique car l'application que je développe est très simple et il y a peu de risque d'avoir des effets de bord.
Ou au contraire, tu peux devenir un "intégriste" du typage des données et prendre la main sur chacune d'entre elles. It's up to you.
Il est aussi possible d'en faire un mix. Certains scripts peuvent nécessiter d'avoir des types de données inscrits dans le marbre et à ce moment là tu utiliseras declare(strict_types=1)
uniquement sur ces fichiers.
Fun fact : Caleb Porzio créateur entre autres d'Apine.js n'aime pas trop les types, cela ne l'empêche pas de faire des trucs incroyables.
declare(strict_types=1)
Je te liste ici d'autres articles que j'ai pu trouver sur le sujet et qui m'ont aidé à consolider cet article.
Merci à Ludovic (@LaravelJutsu) et Fred (@FredBouchery) pour leurs relectures attentives et leurs suggestions afin d'améliorer cet article. Si vous aussi, vous avez des suggestions, n'hésitez pas à m'en faire part dans les commentaires ou en me contactant directement.
J'espère que cet article t'aura permis de mieux comprendre l'intérêt de l'instruction declare(strict_types=1)
.
Si tu souhaites d'autres articles de ce type, je te laisse me dire en commentaire quelle notion tu aimerais que je détaille que ce soit en PHP ou autre. Bon après je t'avoue qu'en dehors du dev web mes compétences sont moins affutées mais ce sera toujours un défi intéressant.
Prends soin de toi !