Kodokon kodokon.com

POO moderne : classes, propriétés promues, visibilité

Écrivez des classes PHP 8 idiomatiques : promotion de propriétés, readonly, constructeurs nommés et objets-valeurs immuables.

9 min · 3 questions

Ouvrir cette leçon dans Kodokon

Vous é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
<?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();
Avant / après : la promotion supprime tout le code de recopie.

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
<?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;
Objet-valeur immuable : add() retourne une nouvelle instance.

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
<?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;
Constructeur privé + fabriques statiques : les seuls états valides sont constructibles.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Que fait la promotion de propriétés dans un constructeur PHP 8 ?
    • Elle rend automatiquement toutes les propriétés publiques
    • Elle déclare la propriété et l'assigne depuis le paramètre, en une seule étape
    • Elle génère des accesseurs (getters) pour chaque propriété
    • Elle convertit les propriétés en constantes de classe
  2. Quand une propriété readonly peut-elle être écrite ?
    • Jamais : elle doit recevoir une valeur par défaut à la déclaration
    • Une seule fois, depuis la portée de la classe qui la déclare
    • À tout moment, tant que l'écriture vient de la classe elle-même
  3. Quelle visibilité choisir pour une propriété que seules la classe et ses classes filles doivent utiliser ?
    • public
    • protected
    • private