Comment utiliser les propriétés en lecture seule dans PHP 8.1 –
PHP 8.1 ajoute la prise en charge d’un readonly
modificateur sur les propriétés de classe. Une propriété marquée de cette manière ne peut être définie qu’une seule fois. Essayer de modifier la valeur d’une propriété en lecture seule après l’initialisation générera une erreur.
« Lecture seule » est un terme assez vague, avec des implications variables selon les langages de programmation individuels. Dans ce contexte, « readonly » signifie en réalité « immuable » : vous pouvez définir la valeur d’une propriété, mais elle ne peut pas être modifiée par la suite.
Sommaire
Écriture de propriétés en lecture seule
Ajouter le readonly
modificateur pour rendre une propriété en lecture seule. Il doit être placé entre le modificateur d’accès de la propriété et son indicateur de type.
class Demo { public string $Mutable; public readonly string $Immutable; public function __construct( string $Mutable, string $Immutable) { $this -> Mutable = $Mutable; $this -> Immutable = $Immutable; } }
$Mutable
est un bien public ordinaire. Vous pouvez modifier sa valeur à tout moment, que ce soit dans les méthodes de classe ou de l’extérieur :
$demo = new Demo("A", "X"); $demo -> Mutable = "B";
$Immutable
est un peu différent. Vous pouvez toujours lire sa valeur quand vous le souhaitez, mais toute modification échouera avec un Error
:
// Throws an Error $demo -> Immutable = "Y";
Le readonly
le modificateur est également pris en charge dans les propriétés de constructeur promues :
class Demo { public function __construct( public readonly string $Immutable="foobar" ) {} }
Vous pouvez toujours définir la propriété manuellement dans votre constructeur lorsque vous utilisez la promotion avec une valeur par défaut. C’est le paramètre de fonction qui reçoit la valeur par défaut, pas l’instance de propriété. La promotion desucres au même code montré dans l’exemple précédent.
Mises en garde
Les propriétés en lecture seule sont une amélioration de la syntaxe simple que vous pouvez adopter à votre guise. Il n’y a pas d’implications de compatibilité descendante et leur utilisation est entièrement facultative. Si vous commencez à les ajouter, il y a quelques mises en garde et limitations à prendre en compte.
Contrairement aux propriétés classiques, les propriétés en lecture seule ne sont pas autorisées à avoir une valeur par défaut dans leur définition :
class Demo { protected readonly string $foo = "bar"; }
Cette instruction définit et initialise $foo
. Vous ne pouvez pas modifier sa valeur après l’initialisation, la propriété est donc en fait une constante. Par conséquent, les valeurs par défaut sont interdites et vous devez plutôt utiliser une vraie constante :
class Demo { const foo = "bar"; }
Suite à cette restriction, readonly
est seulement pris en charge sur les propriétés typées. La propriété suivante a une définition illégale :
class Demo { protected readonly $foo; }
Une propriété non typée, comme $foo
ci-dessus, a une valeur implicite par défaut de null
. Si readonly
était autorisée, la règle « pas de constantes implicites » refait surface. Les propriétés typées font la distinction entre les états « non initialisé » et « null », de sorte qu’elles existent sans aucune valeur jusqu’à ce que vous en définissiez une explicitement.
Le modificateur readonly a des règles spéciales lorsqu’il est utilisé dans le cadre de l’héritage de classe. Impossible d’ajouter ou de supprimer des classes enfants readonly
sur des propriétés définies par leurs parents.
Créer une propriété accessible en écriture readonly
casserait la classe parente si ses méthodes faisaient muter la valeur. Bien que la suppression de la contrainte soit apparemment inoffensive, les vues RFC readonly
comme une « restriction intentionnelle » des capacités qui seraient perdues si les remplacements d’héritage étaient autorisés. C’est interdit pour que les classes parents puissent affirmer que les enfants ne peuvent pas provoquer d’effets secondaires en modifiant les propriétés qui sont censées être en lecture seule.
Les propriétés en lecture seule ne peuvent être définies que dans la portée dans laquelle elles sont définies. Cela signifie que public
les propriétés ne peuvent pas être définies depuis l’extérieur d’une classe, même si elles n’ont pas été initialisées auparavant :
class Demo { public readonly string $foo; } $d = new Demo(); $d -> foo = "bar"; // illegal
L’initialisation doit se produire dans la classe qui définit la propriété. En conséquence, les propriétés en lecture seule sont plus proches des champs immuables d’autres langages de programmation par opposition aux propriétés PHP préexistantes.
Le readonly
le modificateur s’applique également à toutes les écritures. Il ne fait pas de distinction entre l’accès interne et externe. Vous ne pouvez pas avoir une propriété qui est publiquement en lecture seule mais accessible en écriture dans la classe, bien qu’une future extension de spécification puisse le permettre.
Un dernier piège concerne le clone
mot-clé. Ce code ne fonctionnera pas :
class Demo { public function __construct( public string $foo ) {} } $d = new Demo("bar"); $d2 = clone $d; $d2 -> foo = "foobar";
Le clonage suit les mêmes règles que les accès aux propriétés classiques. Même si le changement de foobar
c’est la première fois que foo
est accessible le $d2
, la propriété a déjà été initialisée par le processus de clonage. Il y a une initialisation implicite lors du clonage.
Quand utiliser les propriétés en lecture seule ?
Les propriétés en lecture seule accéléreront considérablement la création de classes simples, qui représentent des structures de données. Il est courant d’écrire des classes jetables pour contenir des paramètres de requête HTTP, des objets de transfert de données et des données de réponse. Celles-ci sont généralement immuables, où les propriétés ne sont pas censées changer après la construction de la classe.
Auparavant, vous aviez deux choix peu attrayants lors de l’écriture de classes de type struct : utiliser des propriétés publiques, accélérer le développement mais autoriser la modification, ou passer du temps à ajouter manuellement des méthodes getter pour exposer les propriétés protégées.
// Not ideal - Properties could be modified externally class UserCreationRequest { public function __construct( public string $Username, public string $Password ) {} } // Not ideal either - Lots of boilerplate code class UserCreationRequest { public function __construct( protected string $Username, protected string $Password ) {} public function getUsername() : string { return $this -> Username; } public function getPassword() : string { return $this -> Password; } }
Les propriétés en lecture seule permettent enfin l’approche idéale :
class UserCreationRequest { public function __construct( public readonly string $Username, public readonly string $Password ) {} }
Les propriétés sont accessibles au public mais immuables. Combinées à la promotion des propriétés du constructeur, les propriétés en lecture seule promettent de réduire considérablement le code passe-partout, vous permettant d’écrire des classes utiles plus rapidement.
readonly
facilite également la lisibilité du code et indique mieux vos intentions. Toute personne lisant ou éditant le UserCreationRequest
classe sait que ses propriétés ne sont pas censées changer. Dans le premier exemple, on ne sait pas si un autre code du projet modifie directement les propriétés de la classe. Le deuxième exemple est un peu plus clair, mais pourrait tout de même inciter un développeur à implémenter des redondances setUsername()
et setPassword()
méthodes.
Conclusion
Le readonly
modifier apporte un support d’immutabilité intégré aux propriétés de classe PHP. Cela rend votre code plus clair et empêche les modifications de valeur involontaires en appliquant l’immuabilité au moment de l’exécution.
En repensant à la série de versions de PHP 7, la création d’une classe de base semblable à une structure impliquait la définition de propriétés typées, l’écriture d’un constructeur qui définissait ces propriétés, puis l’ajout de méthodes getter pour exposer leurs valeurs. Avec PHP 8.1, vous pouvez condenser tout cela en une seule signature de constructeur en combinant public readonly
et promotion immobilière.
Les propriétés en lecture seule sont implémentées dans les dernières versions de développement de PHP 8.1. La version prête pour la production arrivera en novembre 2021.