Écrivez des classes PHP 8 idiomatiques : promotion de propriétés, readonly, constructeurs nommés et objets-valeurs immuables.
Ouvrir cette leçon dans KodokonVous écrivez des classes depuis longtemps, mais PHP 8 a rendu obsolètes plusieurs habitudes. La plus visible : la promotion de propriétés dans le constructeur. Déclarer une visibilité (private, protected, public) devant un paramètre du constructeur crée la propriété et l'assigne en une seule étape. Les trois blocs répétitifs de l'ancien style - déclaration, paramètre, assignation - fusionnent en un seul.
<?php
declare(strict_types=1);
class LegacyProduct
{
private string $name;
private int $priceCents;
public function __construct(
string $name,
int $priceCents,
) {
$this->name = $name;
$this->priceCents = $priceCents;
}
}
final class Product
{
public function __construct(
private string $name,
private int $priceCents,
) {
}
public function label(): string
{
return sprintf(
'%s (%.2f EUR)',
$this->name,
$this->priceCents / 100,
);
}
}
$product = new Product('Keyboard', 4990);
echo $product->label();La visibilité reste votre premier outil d'encapsulation : private par défaut, protected seulement si une classe fille doit y accéder, public en dernier recours. Depuis PHP 8.1, readonly ajoute une garantie plus forte : la propriété n'est inscriptible qu'une seule fois, depuis la portée de la classe qui la déclare. Combinée à la promotion, elle produit des objets-valeurs immuables en quelques lignes : toute « modification » retourne une nouvelle instance, ce qui élimine les effets de bord partagés.
<?php
declare(strict_types=1);
final class Money
{
public function __construct(
public readonly int $amount,
public readonly string $currency,
) {
}
public function add(Money $other): self
{
if ($other->currency !== $this->currency) {
throw new InvalidArgumentException(
'Currency mismatch'
);
}
return new self(
$this->amount + $other->amount,
$this->currency,
);
}
}
$total = (new Money(500, 'EUR'))
->add(new Money(250, 'EUR'));
echo $total->amount;Côté méthodes, deux patterns dominent chez les développeurs confirmés. Les constructeurs nommés : un constructeur private accompagné de fabriques statiques rend chaque intention explicite et interdit les instanciations incohérentes. Les interfaces fluides : retourner $this (mutable) ou new self(...) (immuable) permet de chaîner les appels. Le compromis est connu : la version immuable est plus sûre mais alloue un objet par appel - négligeable presque partout, mesurable dans une boucle chaude.
<?php
declare(strict_types=1);
final class User
{
private function __construct(
public readonly string $email,
public readonly string $role,
) {
}
public static function admin(string $email): self
{
return new self($email, 'admin');
}
public static function member(string $email): self
{
return new self($email, 'member');
}
}
$user = User::admin('lea@example.com');
echo $user->role;readonly peut-elle être écrite ?