Aller au contenu principal

PHP 8.6 : ce qui est acté, ce qui se joue encore.

Découvrez l'état d'avancement de PHP 8.6 à mi-parcours vers sa GA fin 2026. Sept RFCs implémentées, cinq acceptées, et des sujets clés comme les generics au centre des discussions.

MAJ 6 min de lecture
Sommaire · 17

PHP 8.6 vise une GA fin d'année 2026. À mi-chemin, nous allons regarder où en est la future release de PHP. Sept RFCs sont implémentées, cinq acceptées, sept en vote, plusieurs en discussion. Et un sujet à part : les generics, qui font leur retour avec une nouvelle proposition déposée il y a deux jours.

Sept RFCs déjà implémentées

Liste vérifiée sur php.watch/versions/8.6/rfcs. Trois méritent qu'on s'y attarde, les quatre autres tiennent en une ligne.

clamp v2

Signature finale (RFC clamp_v2) :

PHP
clamp(mixed $value, mixed $min, mixed $max): mixed

Borne une valeur entre un min et un max. Accepte tout type comparable : entiers, floats, chaînes (tri alphabétique), DateTimeInterface. Remplace max(min($v, $max), $min) — pattern qu'on retrouve dans la pagination, les dimensions d'image, la normalisation de score. Auteur : kylekatarnls.

Debugable Enums

Le RFC original sur les enums interdisait toutes les méthodes magiques sauf __call, __callStatic, __invoke. Conséquence : impossible d'utiliser __debugInfo() pour customiser la sortie var_dump. Cette restriction saute en 8.6. Désormais une enum peut renvoyer ce qu'elle veut quand on l'inspecte :

enum(Foo::Bar) (1) {
  [0]=> string(14) "Foo::Bar = Baz"
}

(RFC debugable-enums).

enum SortDirection

Une enum native, unbacked (RFC sort_direction_enum) :

PHP
enum SortDirection
{
    case Ascending;
    case Descending;
}

Le choix « unbacked » est explicite : pas de valeur scalaire associée, à chaque application de mapper vers SORT_ASC, 'asc', ou autre selon son besoin.

Les quatre autres

  • isReadable / isWritable reflection methods — checks natifs sur l'accessibilité d'une propriété, utile pour les hydraters et serializers.
  • mysqli_quote_string — quote sans connexion ouverte.
  • Add Form Feed in trim Functions — le caractère \f (form feed, 0x0C) rejoint la liste par défaut des caractères supprimés par trim.
  • Oniguruma maintenance end and end of mbregex — le backend Oniguruma est retiré de ext/mbstring. Les fonctions mb_ereg* continuent à fonctionner avec un backend interne PCRE2.

Cinq RFCs acceptées

Implémentation en cours. Liste complète, focus sur les deux qui changent la façon de coder.

Closure optimizations

Deux gains (RFC closure-optimizations) :

  1. Inférence automatique en static : une closure qui ne peut pas utiliser $this (pas de référence directe, pas de méthode statique appelée, pas de closure imbriquée non-statique, pas de require/include/eval) est convertie en static automatiquement.
  2. Cache des closures stateless : une closure qui ne capture rien et ne déclare aucune variable statique est réutilisée d'un appel à l'autre — la même instance en mémoire. Gain mesuré sur benchmarks synthétiques : « about 80% » selon le RFC.

Effet de bord à retenir : ReflectionFunction::getClosureThis() retourne désormais null pour les closures inférées statiques. Et deux closures stateless lexicalement identiques deviennent le même objet — donc $a === $b peut passer de false à true après upgrade.

Partial Function Application (v2)

Syntaxe finalisée (RFC partial_function_application_v2) :

  • ? : remplace un argument à cette position
  • ... : représente zéro ou plusieurs arguments restants
PHP
$shorten = str_word_count(...);
// $shorten(string $string, int $format = 0, string $characters = "")

$mid = foo(1, ?, 3, ?);
// $mid attend les arguments 2 et 4

Vote : 33 pour, 0 contre, 0 abstention. La v1 de 2021 avait été retoquée sur des cas limites du moteur d'inférence ; cette v2 réduit la surface et passe.

Les trois autres

  • Add pack()/unpack() endianness modifiers for floating-point numbers — les float rejoignent les modifiers < / > qui existaient déjà pour les entiers.
  • Add pack()/unpack() support for endianness modifiers on integers — extension symétrique côté entiers.
  • Exempt input type and value validation from BC Break policy — décision méta : les fixes de validation d'entrée ne déclenchent plus la procédure de BC break complète. Pertinent pour les contributeurs, transparent pour les utilisateurs.

Sept en vote, plusieurs en discussion

À surveiller pour la fin du semestre, sans garantie de vote favorable.

En vote (au 12 mai) : #[\Override] for class constants · Partial Function Application: Handling of Optional Parameters · Stream Error Handling Improvements · Followup Improvements for ext/uri · Secure Session Configuration Defaults · Display Function Arguments in Errors · SNMP improvements.

En discussion : Polling API · True Async · BackedEnum::values().

True Async mérite un mot — c'est la proposition la plus ambitieuse non encore tranchée (RFC true_async). Trois primitives : spawn(), await(), suspend(). Le système englobe les Fibers existants, ajoute un Scheduler et un Reactor (boucle événementielle), un mécanisme de cancellation coopératif, et une détection de deadlock natif. Si ça passe, c'est plus structurant que toutes les autres réunies — mais le statut Draft suggère qu'on en reparlera surtout pour PHP 9.0.

Le sujet à part : Bound-Erased Generic Types

C'est le retour des generics, toujours en discussion au 12 mai. Trois caractéristiques qui rendent cette proposition différente des tentatives précédentes.

Scope large

Selon le texte du RFC : « Generic type parameters can be declared on classes, interfaces, traits, functions, methods, closures, and arrow functions. »

Donc tout. Pas un compromis « interfaces seulement » comme certaines propositions intermédiaires.

Type erasure plutôt qu'enforcement runtime

« Type parameters erase to their bound at runtime; the pre-erasure form is preserved for Reflection and consumed by static analyzers. »

Les bornes (<T extends Stringable>) sont vérifiées par les outils d'analyse statique (PHPStan, Psalm). À l'exécution, le moteur traite T comme sa borne — Stringable dans cet exemple. Aucun coût runtime ajouté. La métadonnée pre-erasure est conservée pour la Reflection, ce qui permet aux IDE et aux libs comme Doctrine de la lire si besoin.

Static analysis plutôt que compile-time enforcement

C'est le compromis explicite : le RFC « emphasizes static analysis rather than compile-time enforcement ». Concrètement, un code générique faux ne sera pas refusé par le parseur PHP — il sera juste détecté comme erreur par PHPStan. La voix de Gmati dans le débat : PHP utilise déjà des generics par docblock (@template) sans enforcement runtime ; cette RFC ne fait que formaliser la pratique dans la syntaxe native.

Ce que ça donnerait

PHP
interface Collection<T>
{
    public function add(T $item): void;
    public function first(): ?T;
}

final class PostCollection implements Collection<Post>
{
    public function add(Post $item): void { /* T = Post */ }
    public function first(): ?Post { /* T = Post */ }
}

À l'exécution, T est traité comme mixed (ou la borne déclarée). Mais PHPStan, Psalm, PHPStorm verront Post et inféreront en conséquence.

Calendrier

Le RFC vient d'être proposé. Pour entrer en 8.6, il faudrait un vote favorable avant la fin de l'été 2026. Trois mois pour qu'une RFC d'ampleur passe sur un sujet qui débat depuis 2016 — c'est court. Le débat sur internals porte d'ailleurs déjà sur un point classique : des generics non-enforced créent-ils plus de confusion qu'ils n'en évitent ?

La suite

PHP 8.6 ressemble à une release d'incrément propre : des utilities qui rangent du legacy, des optimisations gratuites, et une RFC qui pourrait être structurante si le calendrier le permet. On regarde l'évolution du vote generics sur les prochaines semaines.

Activez uniquement ce que vous souhaitez. Vos choix sont conservés 6 mois.

Strictement nécessaires

Indispensables au fonctionnement du site (session, sécurité, préférence d'affichage). Aucune donnée n'est partagée à des tiers et aucun consentement n'est requis.

Toujours actif

Mesure d'audience

Statistiques anonymes via Umami Cloud (hébergement UE) : pages vues, source du trafic, navigateur. Pas de cookie tiers, pas de profilage, pas de partage commercial.