## Déclarations de type

Les déclarations de types peuvent être ajoutées aux arguments des fonctions, valeurs de retour, et à partir de PHP 7.4.0, les propriétés de classe, et à partir de PHP 8.3.0, les constantes de classe. Elles assurent que la valeur est du type spécifié au moment de l'appel, sinon une TypeError est lancée.

Chaque type pris en charge par PHP, à l'exception du type resource, peut être utilisé dans une déclaration de type par l'utilisateur. Cette page contient un journal des modifications de la disponibilité des différents types et de la documentation sur leur utilisation dans les déclarations de type.

> Note:

> Lorsqu'une classe implémente une méthode d'interface ou réimplémente une méthode qui a déjà été définie par une classe parente, elle doit être compatible avec la définition susmentionnée. Une méthode est compatible si elle suit les règles de variance.

### Historique

Version | Description
--- | ---
8.3.0 | Ajout du support pour les constantes typées de classe, interface, trait, et enum.
8.2.0 | Ajout du support de type DNF (Forme Normale Disjonctive).
8.2.0 | Ajout du support du type true.
8.2.0 | Les types null et false peuvent désormais être utilisés de manière autonome.
8.1.0 | La prise en charge des types d’intersection a été ajoutée.
8.1.0 | Le renvoi par référence à partir d’une fonction void est désormais déconseillé.
8.1.0 | La prise en charge du type de retour uniquement never a été ajoutée.
8.0.0 | Ajout du support de mixed
8.0.0 | La prise en charge du type de retour uniquement static a été ajoutée.
8.0.0 | La prise en charge des types union a été ajoutée.
7.4.0 | Ajout du support du typage des propriétés de classe.
7.2.0 | Ajout du support pour object.
7.1.0 | Ajout du support pour iterable.
7.1.0 | Ajout du support pour void.
7.1.0 | La prise en charge des types nullable a été ajoutée.

### Notes d'utilisation des types atomiques

Les types atomiques ont un comportement direct avec quelques mises en garde mineures qui sont décrites dans cette section.

#### Types scalaires

Avertissement

Les alias pour les types scalaires (bool, int, float, string) ne sont pas supportés. À la place, ils sont traités comme des noms de classe ou d'interface. Par exemple, utiliser `boolean` comme une déclaration de type nécessite que la valeur soit une `instanceof` de la classe ou interface `boolean`, plutôt que de type bool :

    <?php
        function test(boolean $param) {}
        test(true);
    ?>

Résultat de l'exemple ci-dessus en PHP 8 :

    Warning: "boolean" will be interpreted as a class name. Did you mean "bool"? Write "\boolean" to suppress this warning in /in/9YrUX on line 2

    Fatal error: Uncaught TypeError: test(): Argument #1 ($param) must be of type boolean, bool given, called in - on line 3 and defined in -:2
    Stack trace:
    #0 -(3): test(true)
    #1 {main}
      thrown in - on line 2

#### void

> Note:

> Le retour par référence à partir d’une fonction void est obsolète à partir de PHP 8.1.0, car une telle fonction est contradictoire. Auparavant, elle émettait déjà les `E_NOTICE` suivants lorsqu’elle était appelée : Only variable references should be returned by reference.

>     <?php
>     function &test(): void {}
>     ?>

#### Types Callable

Ce type ne peut pas être utilisé comme déclaration de type de propriété de classe.

> Note: Il n’est pas possible de spécifier la signature de la fonction.

#### Déclarations de type sur les paramètres de référence

Si un paramètre passé par référence a une déclaration de type, le type de la variable n’est vérifié qu’à l’entrée de la fonction, au début de l’appel, mais pas lorsque la fonction retourne. Cela signifie qu’une fonction peut modifier le type de la variable passée par référence.

Exemple #1 Paramètre typé passé par référence

    <?php
    function array_baz(array &$param)
    {
        $param = 1;
    }
    $var = [];
    array_baz($var);
    var_dump($var);
    array_baz($var);
    ?>

Résultat de l'exemple ci-dessus est similaire à :

    int(1)

    Fatal error: Uncaught TypeError: array_baz(): Argument #1 ($param) must be of type array, int given, called in - on line 9 and defined in -:2
    Stack trace:
    #0 -(9): array_baz(1)
    #1 {main}
      thrown in - on line 2

### Notes d’utilisation des types composites

Les déclarations de type composite sont soumises à quelques restrictions et effectueront un contrôle de redondance au moment de la compilation pour éviter les bogues simples.

Attention

Avant PHP 8.2.0 et l’introduction des types DNF, il n’était pas possible de combiner les intersections de type avec les unions de type.

#### Types d’unions

Avertissement

Il n’est pas possible de combiner les deux types de singleton `false` et `true` ensemble dans une union de type. Utiliser plutôt bool.

Attention

Avant PHP 8.2.0, comme false et null ne pouvaient pas être utilisés comme types autonomes, une union de type composée uniquement de ces types n’était pas autorisée. Cela comprend les types suivants : false, `false|null` et ?false.

##### Sucre syntaxique de type nullable

Une déclaration de type de base unique peut être marquée comme valeur NULL en faisant précéder le type d’un point d’interrogation (`?`). Ainsi `?T` et `T|null` sont identiques.

> Note: Cette syntaxe est prise en charge à partir de PHP 7.1.0, et est antérieure à la prise en charge généralisée des unions de type.

> Note:

> Il est également possible d’obtenir des arguments nullable en faisant de `null` la valeur par défaut. Ceci n’est pas recommandé, car si la valeur par défaut est modifiée dans une classe enfant, une violation de compatibilité de type sera déclenchée car le type null devra être ajouté à la déclaration de type. Ce comportement est également déprécié à partir de PHP 8.4.

> Exemple #2 Ancienne façon de rendre les arguments nullables

>     <?php
>     class C {}

>     function f(C $c = null) {
>         var_dump($c);
>     }

>     f(new C);
>     f(null);
>     ?>

> L'exemple ci-dessus va afficher :

>     object(C)#1 (0) {
>     }
>     NULL

#### Types dupliqués et redondants

Pour détecter des bogues simples dans les déclarations de type composite, les types redondants qui peuvent être détectés sans effectuer de chargement de classe entraîneront une erreur de compilation. Cela comprend :

- Chaque type résolu par nom ne peut se produire qu’une seule fois. Les types tels que `int|string|INT` ou `Countable&Traversable&COUNTABLE` génèrent une erreur.
- L’utilisation de mixed ou never entraîne une erreur.
- Pour les types d’unions :
  - Si bool est utilisé, false ou true ne peut pas être utilisé en plus.
  - Si object est utilisé, les types de classe ne peuvent pas être utilisés en plus.
  - Si iterable est utilisé, array et Traversable ne peuvent pas être utilisés en plus.
- Pour les types d’intersections :
  - L’utilisation d’un type qui n’est pas un type de classe génère une erreur.
  - L’utilisation de self, parent ou static entraîne une erreur.
- Pour les types DNF :
  - Si un type plus générique est utilisé, le plus restrictif est redondant.
  - Utilisation de deux types d’intersection identiques.

> Note: Cela ne garantit pas que le type est « minimal », car cela nécessiterait de charger tous les types de classe utilisés.

Par exemple, si `A` et `B` sont des alias de classe, alors `A|B` reste une union de type légale, même s'il est possible de réduire à `A` ou `B`. De même, si la classe `B extends A {}`, alors `A|B` est également une union de type légale, même s'il pourrait être réduit au type `A` uniquement.

    <?php
    function foo(): int|INT {} // Non autorisé
    function foo(): bool|false {} // Non autorisé
    function foo(): int&Traversable {} // Non autorisé
    function foo(): self&Traversable {} // Non autorisé

    use A as B;
    function foo(): A|B {} // Non autorisé ("use" fait partie de la résolution de noms)
    function foo(): A&B {} // Non autorisé ("use" fait partie de la résolution de noms)

    class_alias('X', 'Y');
    function foo(): X|Y {} // Autorisé (la redondance n'est connue qu'au moment de l'exécution)
    function foo(): X&Y {} // Autorisé (la redondance n'est connue qu'au moment de l'exécution)
    ?>

### Exemples

Exemple #3 Déclaration de type de classe de base

    <?php
    class C {}
    class D extends C {}

    // Ceci n'étend pas C.
    class E {}

    function f(C $c) {
        echo get_class($c)."\n";
    }

    f(new C);
    f(new D);
    f(new E);
    ?>

Résultat de l'exemple ci-dessus en PHP 8 :

    C
    D

    Fatal error: Uncaught TypeError: f(): Argument #1 ($c) must be of type C, E given, called in /in/gLonb on line 14 and defined in /in/gLonb:8
    Stack trace:
    #0 -(14): f(Object(E))
    #1 {main}
      thrown in - on line 8

Exemple #4 Déclaration de type d’interface de base

    <?php
    interface I { public function f(); }
    class C implements I { public function f() {} }

    // Ceci n'implémente pas I.
    class E {}

    function f(I $i) {
        echo get_class($i)."\n";
    }

    f(new C);
    f(new E);
    ?>

Résultat de l'exemple ci-dessus en PHP 8 :

    C

    Fatal error: Uncaught TypeError: f(): Argument #1 ($i) must be of type I, E given, called in - on line 13 and defined in -:8
    Stack trace:
    #0 -(13): f(Object(E))
    #1 {main}
      thrown in - on line 8

Exemple #5 Déclaration de type de retour de base

    <?php
    function sum($a, $b): float {
        return $a + $b;
    }

    // À noter qu'un float sera retourné.
    var_dump(sum(1, 2));
    ?>

L'exemple ci-dessus va afficher :

    float(3)

Exemple #6 Renvoi d’un objet

    <?php
    class C {}

    function getC(): C {
        return new C;
    }

    var_dump(getC());
    ?>

L'exemple ci-dessus va afficher :

    object(C)#1 (0) {
    }

Exemple #7 Déclaration de type d’argument nullable

    <?php
    class C {}

    function f(?C $c) {
        var_dump($c);
    }

    f(new C);
    f(null);
    ?>

L'exemple ci-dessus va afficher :

    object(C)#1 (0) {
    }
    NULL

Exemple #8 Déclaration de type de retour nullable

    <?php
    function get_item(): ?string {
        if (isset($_GET['item'])) {
            return $_GET['item'];
        } else {
            return null;
        }
    }
    ?>

Exemple #9 Déclaration de type pour les propriétés de classe

    <?php
    class User {
        public static string $foo = 'foo';

        public int $id;
        public string $username;

        public function __construct(int $id, string $username) {
            $this->id = $id;
            $this->username = $username;
        }
    }
    ?>

### Typage Strict

Par défaut, PHP va convertir les valeurs d'un mauvais type vers le type scalaire attendu tant que possible. Par exemple, une fonction, qui attend comme paramètre une string, à laquelle est passée un int recevra une variable de type string.

Il est possible d'activer le mode de typage strict fichier par fichier. Dans le mode strict, seule une variable correspondant exactement au type attendu dans la déclaration sera acceptée sinon une TypeError sera lancée. La seule exception à cette règle est qu'une valeur de type int peut passer une déclaration de type float.

Avertissement

Les appels aux fonctions depuis des fonctions internes ne seront pas affectés par la déclaration `strict_types`.

Pour activer le mode strict, l'expression `declare` est utilisée avec la déclaration `strict_types` :

> Note:

> Le typage strict s'applique aux appels de fonction effectués depuis l'intérieur d'un fichier dont le typage strict est actif, et non aux fonctions déclarées dans ce fichier. Si un fichier dont le typage strict n'est pas activé effectue un appel à une fonction qui a été définie dans un fichier dont le type strict est actif, la préférence de l'appelant (mode coercitif) sera respectée et la valeur sera forcée.

> Note:

> Le typage strict n'est défini que pour les déclarations de type scalaire.

Exemple #10 Typage strict pour les valeurs d'arguments

    <?php
    declare(strict_types=1);

    function sum(int $a, int $b) {
        return $a + $b;
    }

    var_dump(sum(1, 2));
    var_dump(sum(1.5, 2.5));
    ?>

Résultat de l'exemple ci-dessus en PHP 8 :

    int(3)

    Fatal error: Uncaught TypeError: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 9 and defined in -:4
    Stack trace:
    #0 -(9): sum(1.5, 2.5)
    #1 {main}
      thrown in - on line 4

Exemple #11 Typage coercitif pour les valeurs d'arguments

    <?php
    function sum(int $a, int $b) {
        return $a + $b;
    }

    var_dump(sum(1, 2));

    // Ceux-ci seront convertis en entiers : à noter la sortie ci-dessous !
    var_dump(sum(1.5, 2.5));
    ?>

L'exemple ci-dessus va afficher :

    int(3)
    int(3)

Exemple #12 Typage strict pour les valeurs de retour

    <?php
    declare(strict_types=1);

    function sum($a, $b): int {
        return $a + $b;
    }

    var_dump(sum(1, 2));
    var_dump(sum(1, 2.5));
    ?>

L'exemple ci-dessus va afficher :

    int(3)

    Fatal error: Uncaught TypeError: sum(): Return value must be of type int, float returned in -:5
    Stack trace:
    #0 -(9): sum(1, 2.5)
    #1 {main}
      thrown in - on line 5

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open