PHP 8.1 : ce qui change vraiment
PHP 8.1 a introduit plusieurs fonctionnalités qui changent réellement la façon d’écrire du code robuste : les enums, les propriétés en lecture seule, les fibers, le type never, la syntaxe de callable de première classe, et les types d’intersection.
Sommaire
Le problème #
Chaque nouvelle version majeure de PHP fait l’objet d’un article de blog listant “toutes les nouveautés”, souvent difficile à distinguer entre ce qui change vraiment la façon d’écrire du code et ce qui relève du détail interne ou de la niche. En entretien, on attend une réponse précise et factuelle sur PHP 8.1 : quelles fonctionnalités existent réellement dans cette version, à quoi elles servent, et quel problème concret elles résolvent — pas une liste approximative mélangeant plusieurs versions du langage.
L’idée générale #
PHP 8.1 (sorti fin 2021) a introduit six changements qui modifient réellement la manière d’écrire du code PHP robuste et expressif : les enums, les propriétés readonly, les fibers, le type de retour never, la syntaxe de callable de première classe, et les types d’intersection. Chacun répond à un manque précis du langage, présent depuis longtemps.
Analogie du quotidien #
PHP 8.1, c’est comme une mise à jour d’un atelier de menuiserie qui ne change pas le bois utilisé, mais qui ajoute des outils précis pour des tâches jusque-là bricolées à la main. Avant, pour garantir qu’une pièce de bois ne bouge plus une fois assemblée, il fallait la clouer soi-même à plusieurs endroits en espérant ne rien oublier (l’équivalent d’une convention de code pour l’immutabilité). Avec readonly, l’établi lui-même refuse de bouger la pièce une fois qu’elle est fixée — ce n’est plus une discipline à respecter, c’est une contrainte physique de l’outil.
Diagramme #
Exemple de code #
Enums #
Avant PHP 8.1 (constantes de classe, sans garantie de type) :
<?php
class StatutCommande
{
const EN_ATTENTE = 'en_attente';
const EXPEDIEE = 'expediee';
const LIVREE = 'livree';
}
function changerStatut(string $statut): void
{
// Rien n'empêche d'appeler changerStatut('nimporte_quoi')
}
Avec PHP 8.1 :
<?php
enum StatutCommande: string
{
case EnAttente = 'en_attente';
case Expediee = 'expediee';
case Livree = 'livree';
public function libelle(): string
{
return match ($this) {
self::EnAttente => 'En attente',
self::Expediee => 'Expédiée',
self::Livree => 'Livrée',
};
}
}
function changerStatut(StatutCommande $statut): void
{
// Seule une valeur valide de l'enum peut être passée ici, vérifié par PHP
}
changerStatut(StatutCommande::Expediee);
Propriétés readonly #
Avant PHP 8.1 (immutabilité par convention uniquement) :
<?php
final class Prix
{
private float $montant;
public function __construct(float $montant)
{
$this->montant = $montant;
}
public function montant(): float
{
return $this->montant;
// Rien n'empêche une autre méthode de la classe de modifier $this->montant plus tard
}
}
Avec PHP 8.1 :
<?php
final class Prix
{
public function __construct(
public readonly float $montant,
) {}
}
$prix = new Prix(42.0);
// $prix->montant = 100.0; // Error: Cannot modify readonly property Prix::$montant
Fibers #
Avant PHP 8.1, suspendre puis reprendre une fonction au milieu de son exécution nécessitait des générateurs (limités à yield) ou des bibliothèques externes s’appuyant sur des extensions bas niveau.
Avec PHP 8.1 :
<?php
$fiber = new Fiber(function (): void {
echo "Début\n";
$valeur = Fiber::suspend('pause');
echo "Reprise avec : $valeur\n";
});
$resultatSuspension = $fiber->start(); // affiche "Début", puis suspend
echo "Reçu du fiber : $resultatSuspension\n"; // "pause"
$fiber->resume('valeur reprise'); // affiche "Reprise avec : valeur reprise"
Les fibers sont une brique de bas niveau : en pratique, la plupart des développeurs les utilisent indirectement, via un framework ou une bibliothèque asynchrone construite dessus.
Le type never #
Avant PHP 8.1, rien ne permettait d’exprimer dans la signature qu’une fonction ne retourne jamais normalement (elle lève systématiquement une exception ou termine le script) :
<?php
function echouer(string $message)
{
throw new RuntimeException($message);
// Le type de retour reste ambigu pour les outils d'analyse statique
}
Avec PHP 8.1 :
<?php
function echouer(string $message): never
{
throw new RuntimeException($message);
}
function traiter(?string $valeur): string
{
if ($valeur === null) {
echouer('Valeur manquante');
}
return $valeur; // Les analyseurs statiques comprennent que $valeur est forcément string ici
}
First-class callable syntax #
Avant PHP 8.1, référencer une méthode existante comme callable demandait une chaîne ou un tableau, sans vérification à l’écriture :
<?php
$callable = 'strlen';
$callableMethode = [$objet, 'maMethode'];
Avec PHP 8.1 :
<?php
$callable = strlen(...);
$callableMethode = $objet->maMethode(...);
$longueurs = array_map(strlen(...), ['a', 'bb', 'ccc']);
Cette syntaxe est vérifiée par le moteur PHP au moment de l’écriture (la méthode ou fonction doit exister), contrairement aux chaînes ou tableaux, qui échouent seulement à l’exécution.
Intersection types #
Avant PHP 8.1, un paramètre ne pouvait exiger qu’un seul type à la fois — impossible de dire “cet objet doit implémenter à la fois Countable et Iterator” sans créer une interface dédiée qui combine les deux artificiellement.
Avec PHP 8.1 :
<?php
function traiter(Countable&Iterator $collection): void
{
// $collection doit implémenter à la fois Countable ET Iterator
echo count($collection);
}
Quand se pencher sur PHP 8.1 ? #
- Au démarrage d’un nouveau projet : les enums et les propriétés readonly changent souvent la façon de modéliser des objets de valeur et des ensembles fermés de constantes — autant les adopter dès la conception plutôt que de migrer plus tard.
- Lors d’une montée de version d’un projet existant : readonly et never demandent une vérification manuelle des classes concernées (une propriété readonly ne peut plus être modifiée après coup, y compris par du code qui en dépendait implicitement).
- En entretien technique, quand la question porte spécifiquement sur “les nouveautés de PHP récentes” : préciser explicitement la version évite de mélanger des fonctionnalités d’autres versions (comme les named arguments ou les union types, qui datent de PHP 8.0, ou les enums readonly par défaut ou les classes readonly, arrivées seulement en PHP 8.2 et 8.3).
- Pour les fibers spécifiquement : rarement utile en usage direct dans du code applicatif classique — pertinent surtout si vous évaluez ou contribuez à un framework ou une bibliothèque asynchrone.
Points importants #
- Les enums PHP 8.1 existent en deux variantes : les pure enums (sans valeur associée) et les backed enums (avec une valeur
stringouintassociée à chaque cas, comme dans l’exemple ci-dessus) — seuls les backed enums peuvent être convertis depuis/vers une valeur scalaire (from(),tryFrom()). readonlys’applique à une propriété typée : elle ne peut être assignée qu’une seule fois, depuis l’intérieur de la classe qui la déclare (typiquement le constructeur) — toute tentative ultérieure, même depuis une méthode de la même classe, lève une erreur.- Ne pas confondre avec des fonctionnalités de versions voisines : les classes entièrement
readonly(au niveau de la classe, pas juste de la propriété) datent de PHP 8.2, tout comme les types autonomestrue/false/null. Les first-class enum in const expressions et d’autres raffinements arrivent dans des versions encore plus récentes. - Ces fonctionnalités sont indépendantes les unes des autres : on peut très bien adopter les enums et readonly sans jamais toucher aux fibers, qui répondent à un besoin beaucoup plus spécifique (construire des mécanismes de concurrence coopérative).
🐻 À retenir
- ●Les enums remplacent les constantes de classe éparpillées par un type à part entière, vérifié par le moteur PHP — fini les chaînes ou entiers magiques sans garantie de valeur valide.
- ●readonly interdit la modification d’une propriété après son initialisation dans le constructeur : c’est l’immutabilité imposée par le langage, pas seulement par convention.
- ●Les fibers sont une brique bas niveau pour la concurrence coopérative — la plupart des développeurs ne les manipulent jamais directement, mais elles servent de fondation aux frameworks asynchrones modernes (comme certaines parties de Symfony ou ReactPHP/AMPHP).