PHP 8.3.4 Released!

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 classes. Elles assurent que les valeurs sont du type spécifié au temps 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 type 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 à 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 est de nouveau appelée. 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

Antérieur à 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 valeur false et true ensemble dans une union de type. Utilisez plutôt bool.

Attention

Antérieur à PHP 8.2.0, comme false et null ne pouvaient pas être utilisés comme types autonomes, une union de type composé uniquement de ces types n’était pas autorisé. 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.

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 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 type 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 {} // Disallowed
function foo(): bool|false {} // Disallowed
function foo(): int&Traversable {} // Disallowed
function foo(): self&Traversable {} // Disallowed

use A as B;
function
foo(): A|B {} // Disallowed ("use" is part of name resolution)
function foo(): A&B {} // Disallowed ("use" is part of name resolution)

class_alias('X', 'Y');
function
foo(): X|Y {} // Allowed (redundancy is only known at runtime)
function foo(): X&Y {} // Allowed (redundancy is only known at runtime)
?>

Exemples

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

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

// This doesn't extend 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() {} }

// This doesn't implement 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;
}

// Note that a float will be returned.
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 levé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é 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));

// These will be coerced to integers: note the output below!
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
add a note

User Contributed Notes 2 notes

up
18
toinenkayt (ta at ta) [iwonderr] gmail d
2 years ago
While waiting for native support for typed arrays, here are a couple of alternative ways to ensure strong typing of arrays by abusing variadic functions. The performance of these methods is a mystery to the writer and so the responsibility of benchmarking them falls unto the reader.

PHP 5.6 added the splat operator (...) which is used to unpack arrays to be used as function arguments. PHP 7.0 added scalar type hints. Latter versions of PHP have further improved the type system. With these additions and improvements, it is possible to have a decent support for typed arrays.

<?php
declare (strict_types=1);

function
typeArrayNullInt(?int ...$arg): void {
}

function
doSomething(array $ints): void {
(function (?
int ...$arg) {})(...$ints);
// Alternatively,
(fn (?int ...$arg) => $arg)(...$ints);
// Or to avoid cluttering memory with too many closures
typeArrayNullInt(...$ints);

/* ... */
}

function
doSomethingElse(?int ...$ints): void {
/* ... */
}

$ints = [1,2,3,4,null];
doSomething ($ints);
doSomethingElse (...$ints);
?>

Both methods work with all type declarations. The key idea here is to have the functions throw a runtime error if they encounter a typing violation. The typing method used in doSomethingElse is cleaner of the two but it disallows having any other parameters after the variadic parameter. It also requires the call site to be aware of this typing implementation and unpack the array. The method used in doSomething is messier but it does not require the call site to be aware of the typing method as the unpacking is performed within the function. It is also less ambiguous as the doSomethingElse would also accept n individual parameters where as doSomething only accepts an array. doSomething's method is also easier to strip away if native typed array support is ever added to PHP. Both of these methods only work for input parameters. An array return value type check would need to take place at the call site.

If strict_types is not enabled, it may be desirable to return the coerced scalar values from the type check function (e.g. floats and strings become integers) to ensure proper typing.
up
12
crash
2 years ago
The documentation lacks the information, that it's possible to change the return type of a method defined in an interface when the interface's methods return type is defined as `mixed`.

From the RFC:

"The mixed return type could be narrowed in a subclass as this is covariant and is allowed in LSP." (https://wiki.php.net/rfc/mixed_type_v2)

This means the following code is valid in PHP 8.0:

<?php

interface ITest
{
public function
apfel(): mixed; // valid as of 8.0
}

class
Test implements ITest
{
public function
apfel(): array // more explicit
{
return [];
}
}

var_dump((new Test())->apfel());
?>

You can see the result here: https://3v4l.org/PXDB6
To Top