Le 8 décembre 2022, PHP 8.2 introduit les propriétés en lecture seule, déclarées avec le mot-clé readonly devant une propriété typée. Pour un développeur qui modernise l’architecture d’une extension WordPress, la question naturelle est de savoir si cette fonctionnalité apporte une réelle garantie de sécurité, ou si elle n’est qu’une contrainte syntaxique supplémentaire sans effet concret sur la robustesse du code.
La réponse tient en une nuance importante : une propriété readonly ne protège pas contre une mauvaise valeur, elle protège contre une modification après construction. Comprendre cette distinction évite de lui prêter des vertus qu’elle n’a pas.
Définition et règle d’écriture unique
Une propriété déclarée readonly ne peut recevoir une valeur qu’une seule fois, et uniquement depuis le scope de la classe qui la déclare, typiquement dans le constructeur :
final class LigneCommande {
public readonly string $reference;
public readonly int $quantite;
public function __construct( string $reference, int $quantite ) {
$this->reference = $reference;
$this->quantite = $quantite;
}
}
Toute tentative d’écriture ultérieure, y compris depuis l’intérieur de la classe elle-même après la première initialisation, déclenche une erreur fatale Error: Cannot modify readonly property LigneCommande::$quantite. Cette contrainte s’applique aussi bien à une écriture externe qu’à une seconde écriture interne, ce qui la distingue d’un simple modificateur de visibilité private.
Fonctionnement interne : ce qui se passe réellement

PHP marque en interne chaque propriété readonly comme initialisée dès sa première affectation, dans une table de suivi propre à l’instance de l’objet. Une propriété readonly doit obligatoirement être typée : readonly $valeur sans type est une erreur de syntaxe. Elle ne peut pas non plus avoir de valeur par défaut dans sa déclaration, puisque toute valeur par défaut constituerait déjà une première écriture hors du constructeur.
Un point souvent mal compris concerne les objets et tableaux référencés par une propriété readonly : la propriété elle-même ne peut pas être réassignée, mais si elle référence un objet mutable, les propriétés internes de cet objet restent modifiables, sauf si elles sont elles-mêmes déclarées readonly dans leur propre classe.
Cas d’usage dans une extension : les value objects
Le terrain le plus naturel pour readonly dans une extension WordPress est la construction de petits objets de valeur, représentant une donnée métier figée une fois créée : une adresse, un montant, une référence de commande. Là où une extension classique aurait manipulé un tableau associatif array( 'reference' => ..., 'quantite' => ... ), modifiable à tout moment par n’importe quelle fonction qui le reçoit, un objet readonly garantit que la donnée reste identique du début à la fin de son cycle de vie dans le code :
function calculer_total( LigneCommande $ligne, float $prix_unitaire ): float {
// $ligne->quantite est garanti inchangé depuis sa création,
// quel que soit le nombre de fonctions qui l'ont manipulé avant.
return $ligne->quantite * $prix_unitaire;
}
Ce n’est pas qu’une question de style : dans une extension où plusieurs filtres WordPress peuvent successivement modifier une structure de données avant qu’elle n’atteigne son traitement final, un tableau associatif classique laisse la porte ouverte à des modifications indésirables et difficiles à tracer. Un objet readonly, lui, produit une erreur fatale immédiate et explicite dès qu’une tentative de modification survient, ce qui transforme un bug silencieux en erreur détectable au moment du développement.
Pièges à éviter
- Déclarer une propriété
readonlysans type provoque une erreur de syntaxe : le typage est obligatoire, pas optionnel. - Une classe qui hérite d’une classe avec une propriété
readonlyne peut pas redéclarer cette propriété comme non-readonly dans l’enfant : la contrainte se propage. - Cloner un objet contenant des propriétés readonly via
cloneconserve leurs valeurs sans permettre de les modifier ensuite dans__clone(), sauf en PHP 8.3 qui assouplit ce point précis avec la possibilité de réinitialiser une propriété readonly depuis__clone(). - Confondre
readonlyavec une validation de valeur : rien n’empêche d’assigner une valeur incohérente au constructeur, la protection ne porte que sur l’immutabilité après coup, pas sur la pertinence de la donnée initiale.
Ce que readonly ne remplace pas
Les propriétés readonly ne dispensent pas de valider les données en entrée du constructeur. Une classe sérieuse continue de lever une exception si une valeur reçue est invalide, avant même de l’assigner à une propriété readonly :
public function __construct( string $reference, int $quantite ) {
if ( $quantite < 1 ) {
throw new InvalidArgumentException( 'La quantité doit être positive.' );
}
$this->reference = $reference;
$this->quantite = $quantite;
}
Notre verdict
Sur nos extensions migrées vers PHP 8.2, l’introduction de value objects readonly à la place de tableaux associatifs a supprimé une catégorie entière de bugs liés à une modification accidentelle de données en cours de traitement, sans coût de performance mesurable. Cette fonctionnalité mérite d’être adoptée dès qu’une extension impose un minimum de version PHP à 8.2, en particulier sur les structures de données qui traversent plusieurs filtres avant leur usage final.