OUJOOD.COM
Qu'est-ce que le type hinting en PHP ?
Imaginez que vous confiez une mission à un collaborateur. Si vous ne précisez pas de quoi il a besoin, il risque de revenir avec n'importe quoi. Le type hinting fonctionne exactement de la même façon : il permet de dire explicitement à PHP quel type de donnée une fonction ou une méthode attend en paramètre.
Au lieu de découvrir une erreur inattendue en plein fonctionnement de votre application, PHP vous avertit dès le mauvais type est fourni. C'est un garde-fou précieux, surtout quand un projet grandit et que plusieurs développeurs collaborent.
PHP 5 a introduit cette possibilité de manière limitée : on pouvait exiger un objet d'une classe précise ou un tableau. Depuis, chaque version majeure a enrichi ce mécanisme. Aujourd'hui, en PHP 8, les déclarations de type couvrent les types scalaires, les types union, les types intersection et les types nullable. C'est devenu un réflexe indispensable dans tout projet sérieux.
Le typage objet implicite : les bases
Le point de départ est simple : devant le nom d'un paramètre, on indique le type attendu. PHP vérifie alors automatiquement que la valeur fournie correspond au type déclaré. Si ce n'est pas le cas, une erreur fatale est levée.
Aux origines du type hinting, seuls deux types étaient acceptés :
- Un nom de classe, pour exiger que le paramètre soit une instance de cette classe.
- Le mot-clé array, pour imposer un tableau (disponible depuis PHP 5.1).
Passons directement à un exemple concret pour visualiser ce mécanisme.
Exemple avec des classes et un tableau
Cet exemple montre comment une méthode peut exiger un objet d'une classe spécifique, et une autre méthode peut imposer un tableau comme paramètre.
<?php // Définition d'une classe avec deux méthodes typées class MaClasse { // Cette méthode exige un objet de type AutreClasse // Si on passe un autre type, PHP lèvera une erreur fatale public function test(AutreClasse $autreclasse) { echo $autreclasse->var; } // Cette méthode exige un tableau (array) public function testArray(array $tableau) { print_r($tableau); } } // Classe dont l'instance sera passée en paramètre class AutreClasse { public $var = 'Bonjour le monde !'; } // Création des objets $maclasse = new MaClasse; $objet = new AutreClasse; // Appel de test() avec un objet AutreClasse : affiche "Bonjour le monde !" $maclasse->test($objet); echo '<br />'; // Appel de testArray() avec un tableau indexé $tab = array('a', 10, 'b'); $maclasse->testArray($tab); echo '<br />'; // On peut aussi passer directement un tableau littéral $maclasse->testArray(array(10, 'ab', 1254)); ?>
Dans cet exemple, la méthode test() déclare qu'elle attend un objet de type AutreClasse. La variable $objet étant bien une instance de cette classe, l'appel fonctionne sans problème. Si vous tentiez de passer un entier ou une chaîne, PHP déclencherait immédiatement une erreur de type.
La méthode testArray() fonctionne sur le même principe, mais avec le mot-clé array. Toute valeur qui n'est pas un tableau provoquerait une erreur.
Le type hinting avec les fonctions
Le mécanisme ne se limite pas aux méthodes de classe. Les fonctions bénéficient exactement du même système de déclaration de type. La syntaxe est identique : on place le type attendu juste avant le nom du paramètre.
Voici un exemple simple qui illustre cette possibilité.
<?php // Classe simple avec une propriété publique class MaClasse { public $var = 'Bonjour depuis la fonction !'; } // Fonction typée : elle exige un objet de type MaClasse function maFonction(MaClasse $objet) { echo $objet->var; } // Création d'un objet MaClasse $instance = new MaClasse; // Appel de la fonction : tout fonctionne car le bon type est passé maFonction($instance); ?>
Si vous appelez maFonction() avec une valeur qui n'est pas une instance de MaClasse, PHP lèvera une erreur TypeError. Ce comportement vous protège contre les bugs causés par des types inattendus.
Autoriser la valeur NULL avec un type hint
Dans certaines situations, un paramètre peut être optionnel : il reçoit une valeur significative, mais il peut aussi rester vide. Avant PHP 7.1, la seule façon d'accepter NULL en plus d'un type donné était de définir une valeur par défaut à NULL.
Voici comment procéder avec cette approche historique.
<?php // Le paramètre $obj accepte un stdClass OU la valeur NULL // La valeur par défaut NULL rend ce paramètre facultatif function test(stdClass $obj = NULL) { if ($obj === NULL) { echo 'Aucun objet fourni.'; } else { echo 'Objet reçu : ' . get_class($obj); } } // Appel avec NULL : fonctionne grâce à la valeur par défaut test(NULL); // Appel avec un objet stdClass : fonctionne aussi test(new stdClass); // Appel sans argument : fonctionne, NULL est la valeur par défaut test(); ?>
Astuce importante : attention à la différence entre == (comparaison non stricte) et === (comparaison stricte). Un tableau vide [] est converti en NULL par la comparaison non stricte ==, mais pas par ===. Utilisez toujours is_null() ou === si vous devez vérifier précisément si une valeur est NULL.
Depuis PHP 7.1 : la syntaxe nullable avec ?
PHP 7.1 a introduit une notation plus explicite : le symbole ? devant le type. Cette syntaxe indique clairement que le paramètre accepte le type déclaré ou NULL, sans avoir besoin de définir une valeur par défaut.
<?php // Le ? devant stdClass signifie : stdClass ou NULL function traitement(?stdClass $data) { if ($data !== NULL) { echo 'Traitement de l\'objet en cours...'; } else { echo 'Aucune donnée à traiter.'; } } // Appel avec NULL : accepté grâce au ? traitement(NULL); // Appel avec un objet : accepté normalement traitement(new stdClass); ?>
La syntaxe ?Type est plus lisible et plus concise que l'ancienne méthode avec une valeur par défaut. C'est aujourd'hui la manière recommandée de déclarer un paramètre nullable.
Les types scalaires : int, string, float, bool
À l'origine, PHP ne permettait de typer que les objets et les tableaux. Cela posait une limite frustrante : impossible d'exiger qu'un paramètre soit un entier ou une chaîne de caractères.
PHP 7.0 a changé la donne en introduisant le typage des types scalaires. Désormais, vous pouvez déclarer les types suivants :
- int — nombres entiers
- string — chaînes de caractères
- float — nombres à virgule
- bool — valeurs booléennes (true ou false)
Voici un exemple qui montre comment utiliser ces types dans des fonctions.
<?php // Déclaration stricte : PHP appliquera les règles de conversion de type declare(strict_types=1); // Cette fonction exige un entier et retourne un entier function calculerAge(int $anneeNaissance): int { return 2026 - $anneeNaissance; } // Cette fonction exige une chaîne et retourne une chaîne function saluer(string $nom): string { return 'Bonjour, ' . $nom . ' !'; } // Cette fonction exige un booléen function afficherStatut(bool $actif): void { echo $actif ? 'Compte actif' : 'Compte désactivé'; } // Appels valides echo calculerAge(1990); // Affiche : 36 echo saluer('Marie'); // Affiche : Bonjour, Marie ! afficherStatut(true); // Affiche : Compte actif ?>
Notez la directive declare(strict_types=1) en début de fichier. Sans elle, PHP effectue des conversions automatiques silencieuses (par exemple, la chaîne "42" est acceptée comme entier). Avec le mode strict, seule la valeur exacte du type déclaré est acceptée. C'est la configuration recommandée en 2026 pour tout nouveau projet.
Les union types : accepter plusieurs types (PHP 8.0)
Parfois, un paramètre peut légitimement recevoir plusieurs types différents. Par exemple, une fonction d'identification peut accepter un identifiant sous forme d'entier ou de chaîne. Avant PHP 8, il fallait gérer ce cas manuellement dans le corps de la fonction.
PHP 8.0 a introduit les union types, qui permettent de déclarer plusieurs types possibles avec le symbole |.
<?php // Union type : le paramètre peut être un int OU un string function rechercherUtilisateur(int|string $identifiant): void { if (is_int($identifiant)) { echo "Recherche par ID numérique : $identifiant"; } else { echo "Recherche par nom d'utilisateur : $identifiant"; } } // Appel avec un entier rechercherUtilisateur(42); // Appel avec une chaîne rechercherUtilisateur('marie_dupont'); // Autre exemple : une fonction qui accepte un tableau ou null function analyserDonnees(array|null $data): void { if ($data === NULL) { echo 'Aucune donnée disponible.'; } else { echo 'Analyse de ' . count($data) . ' éléments.'; } } analyserDonnees([1, 2, 3]); // Affiche : Analyse de 3 éléments. analyserDonnees(NULL); // Affiche : Aucune donnée disponible. ?>
Les union types rendent le code plus lisible et auto-documenté. En regardant la signature de la fonction, on sait immédiatement quels types sont acceptés, sans avoir à lire l'implémentation.
Types d'intersection et types composites (PHP 8.1+)
PHP 8.1 a ajouté les types d'intersection avec le symbole &. Ils permettent d'exiger qu'un paramètre implémente plusieurs interfaces simultanément. C'est utile quand un objet doit cumuler plusieurs comportements.
<?php // Deux interfaces définissant des comportements distincts interface Loggable { public function toLog(): string; } interface Serializable { public function serialize(): string; } // Cette fonction exige un objet qui implémente les DEUX interfaces function sauvegarder(Loggable&Serializable $objet): void { echo $objet->toLog(); echo $objet->serialize(); } // Classe qui implémente les deux interfaces class Rapport implements Loggable, Serializable { public function toLog(): string { return 'Rapport enregistré dans les logs.'; } public function serialize(): string { return 'Données sérialisées.'; } } // Fonctionne car Rapport implémente Loggable ET Serializable sauvegarder(new Rapport); ?>
Les types d'intersection sont particulièrement utiles dans les architectures orientées interface, où la composition de comportements est préférée à l'héritage profond.
Récapitulatif : quelle version de PHP supporte quoi ?
Voici un tableau récapitulatif pour vous repérer rapidement dans l'historique des déclarations de type.
| Fonctionnalité | Version PHP | Syntaxe |
|---|---|---|
| Typage objet (classe) | PHP 5.0 | NomClasse $param |
| Typage tableau | PHP 5.1 | array $param |
| Types scalaires | PHP 7.0 | int, string, float, bool |
| Types nullable | PHP 7.1 | ?Type $param |
| Union types | PHP 8.0 | Type1|Type2 $param |
| Types d'intersection | PHP 8.1 | Interface1&Interface2 $param |
| Type never | PHP 8.1 | function(): never |
Bonnes pratiques en 2026
Pour tirer pleinement parti des déclarations de type dans vos projets PHP actuels, voici les recommandations essentielles :
- Activez toujours strict_types=1 dans vos fichiers. Cela évite les conversions silencieuses qui masquent des bugs.
- Typez tous vos paramètres et valeurs de retour. Un code sans déclaration de type est un code qui laisse la porte ouverte aux erreurs.
- Préférez les union types aux docblocks quand un paramètre accepte plusieurs types. C'est vérifié à l'exécution, pas seulement par un outil d'analyse.
- Utilisez la syntaxe ?Type pour les paramètres optionnels au lieu de définir NULL comme valeur par défaut.
- Documentez vos types complexes (tableaux associatifs, génériques) avec PHPDoc en complément des déclarations natives, car PHP ne supporte pas encore les types génériques natifs.
Par carabde | Mis à jour le 2 avril 2026