phpday 2022

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

Note:

Lors de la surcharge d'une méthode parente, la méthode enfant doit correspondre son type de retour avec la déclaration de type parente. Si le parent ne définit par de type de retour, la méthode enfant peut en déclarer un.

Types unique

Type Description Version
Nom de classe/interface La valeur doit être une instanceof de la classe ou interface donnée.  
self La valeur doit être une instanceof de la même classe que celle dans laquelle la déclaration de type est utilisée. Peut uniquement être utilisé dans les classes.  
parent La valeur doit être une instanceof du parent de la classe dans laquelle la déclaration de type est utilisée. Peut uniquement être utilisé dans les classes.  
array La valeur doit être un tableau (array).  
callable La valeur doit être un callable valide. Ne peut être utilisé comme déclaration de type de propriété de classe.  
bool La valeur doit être un booléen (bool).  
float La valeur doit être un nombre flottant (float).  
int La valeur doit être un entier (int).  
string La valeur doit être une chaîne de caractères (string).  
iterable La valeur doit être soit un array ou une instanceof Traversable. PHP 7.1.0
object La valeur doit être un objet (object). PHP 7.2.0
mixed La valeur peut être de n'importe quelle valeur. PHP 8.0.0
Avertissement

Les alias pour les types scalaires ci-dessus 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

mixed

mixed est équivalent au typ d'union object|resource|array|string|int|float|bool|null. Disponible à partir de PHP 8.0.0.

Exemples

Exemple #1 Déclaration de type de classe basique

<?php
class {}
class 
extends {}

// This doesn't extend C.
class {}

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 #2 Déclaration de type d'interface basique

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

// This doesn't implement I.
class {}

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 #3 Déclaration de type de retour basique

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

// Note that a float will be returned.
var_dump(sum(12));
?>

L'exemple ci-dessus va afficher :

float(3)

Exemple #4 Retournant un objet

<?php
class {}

function 
getC(): {
    return new 
C;
}

var_dump(getC());
?>

L'exemple ci-dessus va afficher :

object(C)#1 (0) {
}

Type nullable

À partir de PHP 7.1.0, les déclarations de type peuvent être marquées comme nullable en préfixant le nom du type avec un point d'interrogation (?). Ceci signifie que la fonction retourne soit le type spécifié soit null.

Exemple #5 Déclaration de type d'argument nullable

<?php
class {}

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

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

L'exemple ci-dessus va afficher :

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

Exemple #6 Déclaration de type de retour nullable

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

Note:

Il est possible d'accomplir des arguments nullable en définissant la valeur par défaut à null. Ceci n'est pas recommandé, car ceci casse lors de l'héritage.

Exemple #7 Ancienne façon de rendre un argument nullable

<?php
class {}

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 composés

Il est possible de combiner des types simples en des types composés. PHP permet de combiner les types dans les manières suivantes :

  • Union de types simples. À partir de PHP 8.0.0.
  • Intersection des types de classes (noms d'interfaces et de classes). À partir de PHP 8.1.0.
Attention

Il n'est pas possible de combiner les types d'intersection avec les types d'union.

Type d'union

Une déclaration de type d'union accepte les valeurs de plusieurs types simples différents, au lieu d'un seul type. Les types d'union sont spécifiés en utilisant la syntaxe T1|T2|.... Les types d'union sont disponibles à partir de PHP 8.0.0.

Type d'union nullable

Le type null est supporté en tant qu'union, tel que T1|T2|null peut être utilisé pour créer une union nullable. La notation existante ?T est considérée comme un raccourci pour le cas commun T|null.

Attention

null ne peut pas être utilisé comme type autonome.

Le pseudo-type false

Le type littéral false est supporté en tant qu'union et est inclus pour des raisons historiques, car beaucoup de fonctions internes retournent false au lieu de null en cas d'échec. Un exemple classique d'une telle fonction est strpos().

Attention

false ne peut être utilisé comme type autonome (incluant un type nullable autonome). De ce fait, false, false|null et ?false ne sont pas permit.

Attention

Le type littéral true n'existe pas.

Types d'intersection

Une déclaration de type d'intersection accepte les valeurs qui satisfies plusieurs déclarations de type de classes, plutôt qu'une seule. Les types d'intersections sont spécifiés avec la syntaxe T1&T2&.... Les types d'intersections sont disponibles à partir de PHP 8.1.0.

Type redondant et dupliqué

Pour anticiper des bugs simples dans les déclarations de types composés, les types redondants qui peuvent être détectés sans effectuer un chargement des classes résulteront dans une erreur lors de la compilation. Ceci inclus :

  • Chaque type de nom résolu peut apparaitre qu'une seule fois. Les types tels que int|string|INT ou Countable&Traversable&COUNTABLE résulteront en une erreur.
  • Utiliser mixed résultera en une erreur.
  • Pour les types d'union :
    • Si bool est utilisé, false ne peut pas être utilisé additionnellement.
    • Si object est utilisé, les types de classes ne peuvent pas être utilisés additionnellement.
    • Si iterable est utilisé, array et Traversable ne peuvent pas être utilisés additionnellement.
  • Pour les types d'intersection :
    • Utiliser un type qui n'est pas un type de classe résultera en une erreur.
    • Utiliser soit self, parent, ou static résultera en une erreur.

Note: Ceci ne garantie pas que le type soit “minimal”, car faire ainsi 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 continue d'être un type d'union légal, même s'il peut être réduit à soit A ou B. Similairement, si la classe B extends A {}, alors A|B est aussi un type d'union légal, même s'il peut être réduit à juste A.

<?php
function foo(): int|INT {} // Disallowed
function foo(): bool|false {} // Disallowed
function foo(): int&Traversable {} // Disallowed
function foo(): self&Traversable {} // Disallowed
use as B;
function 
foo(): A|{} // Disallowed ("use" is part of name resolution)
function foo(): A&{} // Disallowed ("use" is part of name resolution)
class_alias('X''Y');
function 
foo(): X|{} // Allowed (redundancy is only known at runtime)
function foo(): X&{} // Allowed (redundancy is only known at runtime)
?>

Type uniquement valide comme type de retour

void

void est un type de retour indiquant que la fonction ne retourne pas de valeur. Ainsi il ne peut pas faire partie d'une déclaration de type d'union. Disponible à partir de PHP 7.1.0.

Note:

Retourner par référence d'une fonction void est obsolète à partir de PHP 8.1.0, car une telle fonction est contradictoire. Auparavant, ceci émettait déjà la E_NOTICE suivante quand appelé : Only variable references should be returned by reference.

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

never

never est un type de retour indiquant que la fonction ne retourne pas. Ceci signifie que soit elle appelle exit(), lance une exception, ou est une boucle infinie. Par conséquent, ceci ne peut pas prendre part à une déclaration de type d'union. Disponible à partir de PHP 8.1.0.

never est, en parlance de théorie des types, le type vide. Signifiant que c'est le sous-type de tout autre type et peut remplacer tout type de retour lors de l'héritage.

static

La valeur doit être une instanceof de la même classe que celle où la méthode est appelée. Disponible à partir de PHP 8.0.0.

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 #8 Typage strict pour les valeurs d'arguments

<?php
declare(strict_types=1);

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

var_dump(sum(12));
var_dump(sum(1.52.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 #9 Typage coercitif pour les valeurs d'arguments

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

var_dump(sum(12));

// These will be coerced to integers: note the output below!
var_dump(sum(1.52.5));
?>

L'exemple ci-dessus va afficher :

int(3)
int(3)

Exemple #10 Typage strict pour les valeurs de retour

<?php
declare(strict_types=1);

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

var_dump(sum(12));
var_dump(sum(12.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

Typage coercitif avec les types d'union

Quand strict_types n'est pas activé, les déclarations de types scalaire sont sujets à des coercitions de type implicite limité. Si le type exact de la valeur ne fait pas partie de l'union, alors le type cible est choisie dans l'ordre de préférence suivant :

  1. float
  2. string
  3. bool
Si le type existe dans l'union, et que la valeur peut être forcée dans le type sous les sémantiques existantes de vérification de type de PHP, alors le type est choisi. Sinon le prochain type est essayé.

Attention

Il y a une exception, si la valeur est une chaîne de caractère et que int et float font partie de l'union, alors le type préféré est choisie en fonction des sémantiques de “chaîne numérique”. Par exemple, pour "42" int est choisie, tant que pour "42.0" float est choisie.

Note:

Les types qui ne font pas partie de la liste de préférence ci-dessus ne sont pas des cibles éligibles aux coercitions implicites. En particulier aucune coercition implicite aux types null et false se produit.

Exemple #11 Exemple de types étant forcé dans le type faisant partie de l'union

<?php
// int|string
42    --> 42          // exact type
"42"  --> "42"        // exact type
new ObjectWithToString --> "Result of __toString()"
                      
// object never compatible with int, fall back to string
42.0  --> 42          // float compatible with int
42.1  --> 42          // float compatible with int
1e100 --> "1.0E+100"  // float too large for int type, fall back to string
INF   --> "INF"       // float too large for int type, fall back to string
true  --> 1           // bool compatible with int
[]    --> TypeError   // array not compatible with int or string

// int|float|bool
"45"    --> 45        // int numeric string
"45.0"  --> 45.0      // float numeric string

"45X"   --> true      // not numeric string, fall back to bool
""      --> false     // not numeric string, fall back to bool
"X"     --> true      // not numeric string, fall back to bool
[]      --> TypeError // array not compatible with int, float or bool
?>

Divers

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

Les types déclarés des références des paramètres sont vérifiés lors de l'entrée dans la fonction, mais pas lorsque la fonction retourne, donc après que la fonction a retourné, le type de l'argument a pu être modifié.

<?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 en PHP 8 :

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

Exemple #13 Capturer l'exception de type TypeError

<?php
declare(strict_types=1);

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

try {
    
var_dump(sum(12));
    
var_dump(sum(1.52.5));
} catch (
TypeError $e) {
    echo 
'Error: '$e->getMessage();
}
?>

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

int(3)
Error: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 10
add a note add a note

User Contributed Notes 5 notes

up
9
anisgazig at example dot com
9 months ago
same data type and same value but first function declare as a argument type declaration and return int(7)
and second fucntion declare as a return type declaration but return int(8).

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

var_dump(argument_type_declaration(3.5,4.7));
//output:int(7)

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

var_dump(return_type_declaration(3.5,4.7));

//output:int(8)
up
6
toinenkayt (ta at ta) [iwonderr] gmail d
7 months 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
0
manoj904378 at gmail dot com
2 months ago
PHP Version 7.4
---
true=1;
false=2;

<?php
 
function a(bool $a,bool $b){
    return
$a+$b;
  }
 
 
var_dump(a(false,3.9));
?>
Output
------
int(1)
up
0
Hayley Watson
3 months ago
Not explicit is that function parameters can also have union type declarations; they're not just for property and return value declarations.

<?php

declare(strict_types = 1);

function
foo(int|string $arg)
{
    if(
is_string($arg))
    {
        echo
"It's a string!\n";
    }
    elseif(
is_int($arg))
    {
        echo
"It's an integer!\n";
    }
    else
    {
        echo
"It shouldn't be here!\n";
    }
}

foo(42);
foo('bar');
foo([]);
up
0
crash
3 months 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