PHP 8.4 Alpha 1 est sortie le 6 juin 2024, la feature freeze est tombée le 16 juillet, et la GA pointe le 21 novembre 2024. Le périmètre est désormais figé — plus aucune RFC ne peut entrer. Parmi les fonctionnalités retenues, deux changent en profondeur la façon de modéliser les objets : les property hooks et l'asymmetric visibility. Deux RFC débattues depuis des années sur internals.php.net, qui arrivent enfin sous une forme remarquablement lisible.
Property hooks : la fin du boilerplate getter/setter
Jusqu'ici, dès qu'une propriété nécessitait une logique — validation, transformation, valeur calculée — tu étais condamné au classique duo getXxx() / setXxx(), avec une propriété privée en dessous. Cinq lignes là où une propriété publique aurait suffi à exprimer l'intention. Les property hooks permettent désormais d'attacher directement des blocs get et set à la déclaration de propriété.
<?php
// PHP 8.4 – property hooks
class User
{
public string $fullName {
get => $this->firstName . ' ' . $this->lastName;
}
public string $email {
get => $this->rawEmail;
set(string $value) {
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException("Email invalide : {$value}");
}
$this->rawEmail = strtolower(trim($value));
}
}
private string $rawEmail = '';
public function __construct(
public readonly string $firstName,
public readonly string $lastName,
) {}
}
$user = new User('Flavien', 'Metivier');
$user->email = 'Flavien@Example.COM'; // normalisation automatique
echo $user->fullName; // "Flavien Metivier"
echo $user->email; // "flavien@example.com"Ce qui frappe d'emblée : la syntaxe est non-invasive. Un hook get seul rend la propriété en lecture seule depuis l'extérieur. Un hook set seul laisse la lecture directe de la valeur stockée. La rétrocompatibilité avec les outils d'analyse statique est assurée : PHPStan, Psalm et PhpStorm intègrent déjà la RFC dans leurs builds de preview. Aucune interface publique existante n'est cassée.
Visibilité asymétrique : lire partout, écrire nulle part
L'autre RFC phare, c'est l'asymmetric visibility : une visibilité distincte pour la lecture et l'écriture d'une propriété. La syntaxe public private(set) est limpide — lisible depuis n'importe où, modifiable uniquement depuis la classe elle-même. C'est la réponse PHP aux val/var de Kotlin et aux propriétés init-only de C#, avec une granularité supplémentaire.
Votre dette technique s'accumule ?
Demander un audit →<?php
// PHP 8.4 – asymmetric visibility
class Order
{
public private(set) int $status = 0;
public protected(set) \DateTimeImmutable $updatedAt;
public function __construct(
public readonly string $id,
) {
$this->updatedAt = new \DateTimeImmutable();
}
public function confirm(): void
{
$this->status = 1; // OK : écriture depuis la classe
$this->updatedAt = new \DateTimeImmutable(); // OK : protected(set)
}
}
$order = new Order('ord-001');
echo $order->status; // OK : lecture publique
$order->status = 2; // Fatal error : Cannot modify private(set) propertyContrairement à readonly introduit en PHP 8.1, la propriété reste mutable en interne — tu peux faire transiter une entité entre plusieurs états sans reconstruire l'objet entier. C'est exactement ce qu'on attend d'un agrégat DDD : immutabilité perçue depuis l'extérieur, mutation maîtrisée à l'intérieur.
Ce que ça change concrètement pour tes classes de domaine
- Les Value Objects perdent leurs
getXxx()tout en conservant l'encapsulation :$money->amountau lieu de$money->getAmount() - Les entités Doctrine peuvent exposer leurs propriétés directement sans sacrifier la logique métier dans les setters — Doctrine hydrate par réflexion, ce qui reste compatible
- PHPStan level 9 et Psalm en mode strict continuent de fonctionner : les RFC ont été conçues en tenant compte de l'écosystème d'analyse statique existant
- La convention PSR-12 sur les getters/setters devient optionnelle pour les nouvelles bases de code — les anciennes ne bougent pas
<?php
// PHP 8.3 — en production aujourd'hui
final class Money
{
private function __construct(
private readonly int $amount,
private readonly string $currency,
) {}
public static function of(int $amount, string $currency): self
{
return new self($amount, $currency);
}
public function getAmount(): int { return $this->amount; }
public function getCurrency(): string { return $this->currency; }
}
// ------------------------------------------------
// PHP 8.4 preview — NE PAS déployer avant la GA du 21 nov 2024
final class Money
{
private function __construct(
public readonly int $amount,
public readonly string $currency {
set(string $v) {
if (!in_array($v, ['EUR', 'USD', 'GBP'], true)) {
throw new \DomainException("Devise non supportée : {$v}");
}
$this->currency = strtoupper($v);
}
},
) {}
public static function of(int $amount, string $currency): self
{
return new self($amount, $currency);
}
}
$price = Money::of(4990, 'eur');
echo $price->currency; // 'EUR' — normalisé par le hook setPHP 8.4 ne réinvente pas la roue — il rattrape ce que d'autres langages objet offrent de série, sans pour autant casser vingt ans de code existant. La feature freeze est derrière nous, le périmètre est stable : c'est le bon moment pour évaluer l'impact sur ta base de code avant la GA de novembre. Si tu veux un regard externe sur ta dette OOP et une feuille de route concrète vers PHP 8.4, le Bear Scan est fait pour ça — un audit technique ciblé, livré en une semaine.
Votre dette technique s'accumule ?
Audit complet en 10 jours. Recommandations priorisées et actionnables.