Sortie le 21 novembre 2024, PHP 8.4 est la version qui a le plus changé la façon d'écrire des classes depuis l'arrivée des propriétés typées. La nouveauté phare s'appelle les property hooks : elle permet d'attacher une logique de lecture ou d'écriture directement à une propriété, sans getters ni setters à rallonge. Voici ce qu'il faut retenir pour vos projets, avec des exemples concrets.
Les property hooks : la fin des getters et setters répétitifs
Jusqu'ici, dès qu'une propriété devait être validée ou transformée, on la passait en private et on écrivait deux méthodes. Avec les property hooks, la logique se déclare au même endroit que la propriété :
final class Customer
{
public string $email {
set(string $value) {
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Adresse e-mail invalide');
}
$this->email = strtolower($value);
}
}
public string $displayName {
get => ucfirst($this->firstName) . ' ' . strtoupper($this->lastName);
}
public function __construct(
private string $firstName,
private string $lastName,
) {}
}
Le code appelant reste naturel : $customer->email = 'Jean@Exemple.fr' passe par le hook set, et $customer->displayName est calculé à la lecture. La propriété displayName est dite « virtuelle » : elle n'occupe aucune mémoire, puisqu'elle ne fait référence qu'à d'autres propriétés.
Les property hooks dans les interfaces
Autre avantage, une interface peut désormais exiger une propriété lisible ou modifiable, et plus seulement des méthodes :
interface HasSlug
{
public string $slug { get; }
}
Toute classe qui implémente cette interface doit exposer une propriété slug lisible, qu'il s'agisse d'une propriété classique ou d'un hook calculé.
Quand ne pas les utiliser
Les property hooks ne remplacent pas toutes les méthodes. Une opération coûteuse (requête SQL, appel HTTP) doit rester une méthode explicite : un accès à une propriété doit rester rapide et sans effet de bord surprenant. Gardez les hooks pour la validation, la normalisation et les valeurs dérivées simples.
La visibilité asymétrique
PHP 8.4 permet de donner une visibilité différente à la lecture et à l'écriture. Le cas typique : une propriété lisible par tous, mais modifiable uniquement par la classe elle-même.
final class Invoice
{
public private(set) string $status = 'draft';
public function send(): void
{
$this->status = 'sent';
}
}
$invoice = new Invoice();
echo $invoice->status; // "draft"
$invoice->status = 'paid'; // Error : écriture interdite hors de la classe
C'est plus souple que readonly, qui interdit toute modification après l'initialisation. Pour un objet dont l'état évolue (une facture, une commande), la visibilité asymétrique évite d'écrire un getter juste pour protéger l'écriture.
De nouvelles fonctions pour les tableaux
Quatre fonctions comblent un manque ancien de la bibliothèque standard : array_find(), array_find_key(), array_any() et array_all().
$orders = [
['id' => 12, 'paid' => true],
['id' => 13, 'paid' => false],
];
$firstUnpaid = array_find($orders, fn (array $order) => !$order['paid']);
$allPaid = array_all($orders, fn (array $order) => $order['paid']); // false
$hasUnpaid = array_any($orders, fn (array $order) => !$order['paid']); // true
Fini les foreach avec break ou les array_filter() suivis d'un reset() pour trouver un seul élément.
Instancier sans parenthèses superflues
Petit changement, grand confort : on peut enfin chaîner un appel directement après un new, sans entourer l'instanciation de parenthèses.
// Avant PHP 8.4
$date = (new DateTimeImmutable())->format('Y-m-d');
// Avec PHP 8.4
$date = new DateTimeImmutable()->format('Y-m-d');
Un vrai parseur HTML5 dans l'extension DOM
L'ancienne classe DOMDocument repose sur un parseur HTML 4 qui interprète mal les balises modernes. PHP 8.4 ajoute Dom\HTMLDocument, conforme au standard HTML5, avec en prime la méthode querySelector() que l'on connaît en JavaScript :
$document = Dom\HTMLDocument::createFromString($html);
$title = $document->querySelector('main h2')?->textContent;
Pour un script d'import de contenus ou un outil d'audit SEO maison, c'est un gain de fiabilité important.
L'attribut #[\Deprecated] et les objets paresseux
L'attribut #[\Deprecated] permet de marquer vos propres fonctions et méthodes comme obsolètes : PHP émet alors un avertissement de dépréciation à chaque appel, comme pour ses fonctions internes. Pratique pour faire évoluer une bibliothèque ou un thème sans casser le code existant du jour au lendemain.
PHP 8.4 introduit aussi les lazy objects : un objet peut être créé sans être initialisé, son constructeur n'étant exécuté qu'au premier accès. Vous ne les utiliserez probablement pas directement, mais les conteneurs d'injection de dépendances et les ORM s'en servent pour remplacer leurs proxys générés.
Ce qu'il faut vérifier avant de migrer
La migration depuis PHP 8.3 se passe généralement bien, mais quelques points méritent une vérification :
- Les paramètres implicitement nullables sont dépréciés :
function save(User $user = null)doit devenirfunction save(?User $user = null); - Les dépendances Composer doivent annoncer la compatibilité : lancez
composer update --dry-runaprès avoir changé la contrainte PHP (voir mon article sur Composer et la gestion des dépendances) ; - Les extensions : IMAP, OCI8, PDO_OCI et pspell ont quitté le cœur de PHP pour PECL ;
- Les tests : une suite de tests, même partielle, reste le meilleur filet de sécurité. Mon guide PHPUnit explique comment démarrer.
Côté calendrier, PHP 8.4 bénéficie du support actif jusqu'au 31 décembre 2026, puis des correctifs de sécurité jusqu'au 31 décembre 2028, d'après la page des versions supportées. Si vous êtes encore sur PHP 8.1 ou 8.2, c'est le bon moment pour planifier la montée de version, d'autant que PHP 8.5 est déjà disponible.
En résumé
Les property hooks et la visibilité asymétrique réduisent nettement le code de « plomberie » dans les classes, et les nouvelles fonctions de tableaux rendent le code plus lisible. Vous trouverez la liste complète des changements sur la page officielle de PHP 8.4. Si vous voulez faire le point sur la version de PHP de votre site et sur l'effort de migration, parlons-en.