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) :
clamp(mixed $value, mixed $min, mixed $max): mixedBorne 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"
}enum SortDirection
Une enum native, unbacked (RFC sort_direction_enum) :
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/isWritablereflection 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
trimFunctions — le caractère\f(form feed,0x0C) rejoint la liste par défaut des caractères supprimés partrim. - Oniguruma maintenance end and end of mbregex — le backend Oniguruma est retiré de
ext/mbstring. Les fonctionsmb_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) :
- 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 derequire/include/eval) est convertie enstaticautomatiquement. - 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
$shorten = str_word_count(...);
// $shorten(string $string, int $format = 0, string $characters = "")
$mid = foo(1, ?, 3, ?);
// $mid attend les arguments 2 et 4Vote : 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
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.