Des attributs de type ont été ajoutés dans PHP 7.4 et des améliorations majeures ont été apportées au système de types de PHP. Ces modifications sont totalement facultatives et ne rompent pas les versions précédentes.
Dans cet article, nous allons approfondir cette fonctionnalité, mais résumons d'abord les points les plus importants :
● Elles sont disponibles depuis PHP 7.4
● Elles sont disponible uniquement dans les classes et nécessite des modificateurs d'accès : public, protected ou private ; ou var.
● Tous les types sont autorisés sauf void et callable
eux. Ce qui se passe réellement est ceci :
class Foo { public int $a; public ?string $b = 'foo'; private Foo $prop; protected static string $static = 'default'; }
# non initialisé
Avant d'examiner les choses intéressantes, discutons d'abord d'un aspect important des propriétés de type.
Malgré ce que vous voyez au premier coup d'œil, le code suivant est valide :
class Foo { public int $bar; } $foo = new Foo;
Même si la valeur de $bar n'est pas un entier, après avoir créé un objet Foo, PHP lancera simplement When une erreur se produit, on accède à $bar :
var_dump($foo->bar); Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization
Comme vous pouvez le voir sur le message d'erreur, il y a un nouvel "état de variable" : non initialisé.
Si $bar n'a pas de type, sa valeur sera nulle. Mais les types peuvent être nuls, il n'y a donc aucun moyen de savoir si une propriété de type null a été définie ou simplement oubliée. C'est pourquoi "non initialisé" a été ajouté.
Quatre choses à retenir à propos de la désinitialisation :
● Une propriété non initialisée ne peut pas être lue, ce qui entraînerait une erreur fatale.
Quantity Le statut non initialisé étant vérifié lors de l'accès aux propriétés, il est possible de créer des objets avec des propriétés non initialisées, même si leur type n'est pas nullable.
● Vous pouvez d'abord écrire dans une propriété non initialisée, puis la lire.
● L'utilisation de unset sur une propriété typée la rendra non initialisée, tandis que la suppression d'une propriété non typée la rendra nulle.
En particulier, notez que le code suivant est valide lorsqu'une propriété non initialisée et non nullable est définie après la construction de l'objet
class Foo { public int $a; } $foo = new Foo; $foo->a = 1;
Bien qu'il ne soit vérifié que lors de la lecture de la valeur de la propriété Initialiser état mais effectuez la validation de type lors de l’écriture des valeurs de propriété. Cela signifie que vous pouvez vous assurer qu'un type non valide ne se transforme pas en valeur de propriété.
#Valeurs par défaut et constructeurs
Regardons de plus près comment initialiser une valeur saisie. Pour les types scalaires, une valeur par défaut peut être fournie :
class Foo { public int $bar = 4; public ?string $baz = null; public array $list = [1, 2, 3]; }
Notez que vous ne pouvez utiliser null comme valeur par défaut que si le type est réellement vide. Cela peut sembler évident, mais il existe un ancien comportement avec des paramètres par défaut, qui permettait ce qui suit :
function passNull(int $i = null) { /* … */ } passNull(null);
Heureusement, les attributs de type ne permettent pas ce comportement déroutant.
Notez également que les types d'objets ou de classes ne peuvent pas avoir de valeurs par défaut. Vous devez utiliser des constructeurs pour définir leurs valeurs par défaut.
L'endroit évident pour initialiser une valeur typée est bien sûr le constructeur :
class Foo{ private int $a; public function __construct(int $a) { $this->a = $a; } }
Mais rappelez-vous aussi ce que j'ai mentionné plus tôt : écrire des propriétés non initialisées en dehors du constructeur est valide. Tant que rien n'est lu dans la propriété, la vérification non initialisée n'est pas effectuée.
# Types de types
Alors exactement, que peut-on taper et comment j'ai déjà mentionné que les propriétés typées ne sont valables que dans les classes (pour l'instant), elles ont besoin d'An ? modificateur d'accès ou le mot-clé var les précède.
Pour les types disponibles, presque tous les types peuvent être utilisés sauf void et callable.
Puisque void signifie aucune valeur, il est logique qu'il ne puisse pas être utilisé pour les valeurs saisies. callable est légèrement différent.
Comme vous pouvez le voir, "callable" en PHP peut s'écrire comme ceci :
Mais rappelez-vous aussi ce que j'ai mentionné plus tôt : l'écriture de propriétés non initialisées en dehors du constructeur est valide. Tant que rien n'est lu dans la propriété, la vérification non initialisée n'est pas effectuée.
Voir, un "callable" en PHP peut s'écrire comme ceci :
$callable = [$this, 'method'];
Supposons que vous ayez le code suivant (invalide) :
class Foo { public callable $callable; public function __construct(callable $callable) { /* … */ } } class Bar { public Foo $foo; public function __construct() { $this->foo = new Foo([$this, 'method']) } private function method() { /* … */ } } $bar = new Bar; ($bar->foo->callable)();
Dans ce cas, $callable fait référence à la méthode Private Bar::, mais est appelée dans le contexte de Foo. En raison de ce problème, il a été décidé de ne pas ajouter de support appelable.
Ce n'est pas grave cependant, puisque Closure est un type valide et il se souviendra du contexte $this dans lequel il a été construit.
Au fait, voici la liste de tous les types disponibles :
Quantity bool
Quantity int
Quantity float
Quantity string
Quantity tableau
Quantity itérable
Quantity object
Quantity (nullable)
Quantity self & parent
Quantity Classes & interfaces
# Typage forcé et strict
PHP est un langage dynamique que nous aimons et détestons, il lancera des types autant que possible. En supposant que vous transmettez une chaîne là où un entier est attendu, PHP tentera de convertir automatiquement la chaîne :
function coerce(int $i) { /* … */ } coerce('1'); // 1
Le même principe s'applique aux attributs de type.
Le code ci-dessous est valide et convertit "1" en 1.
class Bar { public int $i; } $bar = new Bar; $bar->i = '1'; // 1
Si vous n'aimez pas ce comportement, vous pouvez le désactiver en déclarant un typage strict :
declare(strict_types=1); $bar = new Bar; $bar->i = '1'; // 1 Fatal error: Uncaught TypeError: Typed property Bar::$i must be int, string used
#Type Différences et héritage
Même PHP 7.4 a introduit des différences de type améliorées, mais les propriétés de type restent inchangées.
Cela signifie que ce qui suit n'est pas valide :
class A {} class B extends A {} class Foo { public A $prop; } class Bar extends Foo { public B $prop; } Fatal error: Type of Bar::$prop must be A (as in class Foo)
Si l'exemple ci-dessus ne semble pas important, vous devriez regarder ce qui suit :
class Foo { public self $prop; } class Bar extends Foo { public self $prop; }
Avant d'exécuter le code, PHP dans les coulisses remplacera self par la classe concrète à laquelle il fait référence.
这意味着在本例中会抛出相同的错误。处理它的唯一方法,是执行以下操作:
class Foo { public Foo $prop; } class Bar extends Foo { public Foo $prop; }
说到继承,您可能会发现很难找到任何好的用例来覆盖继承属性的类型。
虽然我同意这种观点,但值得注意的是,可以更改继承属性的类型,但前提是访问修饰符也从private更改为protected或public。
以下代码有效:
class Foo{ private int $prop; } class Bar extends Foo { public string $prop; }
但是,不允许将类型从可为空的类型更改为不可为空或反向的类型。
class Foo { public int $a; public ?int $b; } class Bar extends Foo { public ?int $a; public int $b; } Fatal error: Type of Bar::$a must be int (as in class Foo)
翻译:https://stitcher.io/blog/typed-properties-in-php-74
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!