Accueil >PHP >Migrer vers PHP 8 >Types en PHP 8 : union, mixed, never et autres

Types en PHP 8 : union, mixed, never et autres

PHP 8 a fortement élargi les types des paramètres, des valeurs de retour et des propriétés : types union, mixed, never, intersections et types des constantes. Une vue d’ensemble par version, avec des exemples et ce qu’impose declare(strict_types=1).

PHP connaît les types des paramètres et des valeurs de retour depuis la version 7.0, les types nullable (?string) et void depuis 7.1, les types des propriétés de classe depuis 7.4. PHP 8 en ajoute d’autres.

Types union (8.0)

Un paramètre, une valeur de retour ou une propriété peut avoir plusieurs types séparés par une barre verticale :

function price(int|float $amount): string
  {
    return number_format($amount, 2)." EUR";
  }
echo price(1500)."\n";
echo price(99.9)."\n";
echo price([10]);

Les deux premiers appels affichent « 1,500.00 EUR » et « 99.90 EUR », le troisième se termine par l’erreur TypeError: price(): Argument #1 ($amount) must be of type int|float, array given.

  • ?string est l’abréviation de string|null. L’abréviation avec le point d’interrogation ne peut pas être combinée avec d’autres types, écrivez int|string|null.
  • Le type false s’utilise comme partie d’une union pour les fonctions qui renvoient false en cas d’erreur – par exemple int|false comme pour strpos().
  • mixed (8.0) désigne n’importe quelle valeur, null compris. Il indique que le type est volontairement souple.
  • static (8.0) comme type de retour d’une méthode signifie « objet de la classe sur laquelle la méthode a été appelée » – utile pour les méthodes qui renvoient $this.
class Query
  {
    protected $conditions = [];
    public function where(string $condition): static
      {
        $this->conditions[] = $condition;
        return $this;
      }
    public function sql(): string
      {
        return "SELECT * FROM articles WHERE ".implode(" AND ", $this->conditions);
      }
  }
echo (new Query())->where("visible = 1")->where("author = ?")->sql();
SELECT * FROM articles WHERE visible = 1 AND author = ?

never (8.1)

Le type de retour never indique que la fonction ne se termine jamais normalement : elle lève toujours une exception ou arrête le script (exit). Le cas typique est une redirection ou une page d’erreur. Si la fonction arrive malgré tout à la fin, PHP lève une erreur :

function abort_page(string $message): never
  {
    echo $message;
  }
abort_page("Page introuvable");

Cela affiche le texte, puis se termine par l’erreur abort_page(): never-returning function must not implicitly return. La fonction devrait se terminer par exemple par exit; ou throw.

Types intersection (8.1) et DNF (8.2)

L’intersection A&B désigne un objet qui remplit les deux types à la fois – généralement deux interfaces :

function print_items(Countable&Traversable $collection): void
  {
    echo count($collection).": ".implode(", ", iterator_to_array($collection));
  }
print_items(new ArrayIterator(["a", "b", "c"]));
3: a, b, c

PHP 8.2 permet de combiner intersections et unions sous la forme normale disjonctive (DNF) : l’intersection est entre parenthèses, par exemple (Countable&Traversable)|array $data ou (A&B)|null.

null, false et true comme types autonomes (8.2)

Depuis PHP 8.2, null et false peuvent aussi être des types autonomes, et le type true s’y est ajouté, si bien que vous pouvez décrire précisément qu’une fonction renvoie par exemple soit un tableau, soit true : array|true.

Constantes de classe typées (8.3)

class Settings
  {
    const string CURRENCY = "EUR";
    const int PER_PAGE = 10;
  }
echo Settings::PER_PAGE." articles par page, prix en ".Settings::CURRENCY;
10 articles par page, prix en EUR

Le type s’applique aussi dans les classes dérivées : une constante ne peut pas être redéfinie dans une sous-classe avec une valeur d’un autre type.

declare(strict_types=1)

Sans ce réglage, PHP convertit dans la mesure du possible les valeurs scalaires vers le type du paramètre – la chaîne "5" transmise à int devient le nombre 5. Avec declare(strict_types=1) au début du fichier, le type doit correspondre exactement (l’exception est un int transmis à un float) :

declare(strict_types=1);
function twice(int $number): int
  {
    return $number * 2;
  }
echo twice(5)."\n";
echo twice("5");

Le second appel se termine par une erreur. En PHP 8, elle s’énonce twice(): Argument #1 ($number) must be of type int, string given, PHP 7.4 signale Argument 1 passed to twice() must be of the type int, string given. Le réglage ne concerne que les appels qui se trouvent dans ce fichier, et declare doit en être la première instruction.

Depuis PHP 8.4, donner à un paramètre typé la valeur par défaut null sans point d’interrogation (string $x = null) est obsolète, voir Changements de PHP 8 qui cassent l’ancien code. Les types des propriétés dans le constructeur et readonly sont décrits dans l’article Constructor promotion et readonly.

Articles connexes :
Constructor promotion et readonly
Changements de PHP 8 qui cassent l’ancien code
Arguments nommés et opérateur nullsafe