logo oujood
🔍

Déclaration de type en PHP : le guide complet

En PHP, la déclaration de type (ou type hinting) vous permet d'imposer le type d'un paramètre lors de l'appel d'une méthode ou d'une fonction. Cette pratique renforce la fiabilité du code et réduit les erreurs d'exécution. Découvrez comment l'utiliser efficacement, des bases du typage objet aux union types introduits en PHP 8.

OUJOOD.COM

PHP cours tutorial

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.

  📋 Copier le code

<?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é.

  📋 Copier le code

<?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.

  📋 Copier le code

<?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.

  📋 Copier le code

<?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.

  📋 Copier le code

<?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 |.

  📋 Copier le code

<?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.

  📋 Copier le code

<?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 PHPSyntaxe
Typage objet (classe)PHP 5.0NomClasse $param
Typage tableauPHP 5.1array $param
Types scalairesPHP 7.0int, string, float, bool
Types nullablePHP 7.1?Type $param
Union typesPHP 8.0Type1|Type2 $param
Types d'intersectionPHP 8.1Interface1&Interface2 $param
Type neverPHP 8.1function(): 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