Il y a quelque temps, j'ai perdu un après-midi à cause d'un réglage de retry fixé à 300. Le développeur qui l'avait écrit pensait en millisecondes. Le worker qui le lisait supposait des secondes, donc chaque job en échec se garait cinq minutes et la file s'est engorgée jusqu'à ce que quelqu'un me bipe. Rien dans le système de types n'aurait pu attraper ça, parce que les deux côtés se contentaient de se passer un int. PHP 8.6, attendu le 19 novembre 2026, s'attaque enfin de front à cette classe de bugs, et c'est ça, plus que n'importe quelle nouvelle syntaxe, qui me fait attendre cette version avec impatience.
<?php
use Time\Duration;
// backoff math stays in duration space, no unit juggling
$base = Duration::fromMilliseconds(100);
$attempt = 5;
$delay = $base->multiplyBy(2 ** $attempt);
$timeout = Duration::fromSeconds(2)
->add(Duration::fromMilliseconds(500));
if ($delay < $timeout) {
usleep($delay->seconds * 1000000);
}La fonctionnalité que tout le monde va montrer en meetup, c'est l'application partielle de fonctions. Tu écris number_format(?, 2, '.', ' ') et tu récupères une closure qui attend l'argument manquant, avec ... pour laisser ouvertes des queues entières de signature. Combinée à l'opérateur pipe, ça veut dire qu'une chaîne de transformations n'a plus besoin d'une fonction fléchée jetable à chaque étape. Ajoute les propriétés readonly avec valeurs par défaut, #[\Override] étendu aux constantes de classe et des enums capables d'implémenter __debugInfo(), et tu as un joli lot. Du bon boulot. Mais mon vote pour la tête d'affiche va à Time\Duration.
Duration est un vrai type valeur pour les intervalles de temps. Tu en construis un avec fromSeconds() ou fromMilliseconds(), et en interne il tient en trois morceaux : les secondes, les nanosecondes et un drapeau de négativité, si bien que 1500 millisecondes deviennent une seconde plus 500 millions de nanosecondes sans que tu fasses l'arithmétique toi-même. Les instances sont immuables, add() et multiplyBy() renvoient des objets neufs, et deux durées se comparent directement avec < et compagnie. Le backoff exponentiel devient une multiplication sur une valeur qui sait ce qu'elle est. On a arrêté de stocker l'argent dans des floats nus il y a des années parce que l'unité se perdait en route ; un timeout stocké comme entier nu, c'est le même piège, et 8.6 le referme enfin.
Autour de cette pièce maîtresse gravitent des standardiseurs plus modestes, que j'appellerais de la législation de confort. clamp($volume, 0, 100) remplace la contorsion du max() enroulé autour d'un min() que chaque base de code réinventait, et il accepte tout ce qui est comparable, DateTimeImmutable inclus. SortDirection arrive comme enum du cœur avec les cas Ascending et Descending, donc l'éternel typage par chaînes des méthodes de repository, 'asc' contre 'ASC' contre true, reçoit un vrai type. Et les messages de JsonException portent désormais des coordonnées : une erreur de syntaxe est signalée près de la position 1:3 au lieu d'un haussement d'épaules quelque part dans un payload de 40 Ko. Chacun de ces ajouts est minuscule. Chacun met aussi à la retraite une fonction helper qui existait en cinq versions incompatibles dans ton répertoire vendor.
Vient ensuite le morceau que les gens du côté serveur devraient étudier : la nouvelle API de polling. Io\Poll\Context permet à un processus d'enregistrer des handles de stream avec des événements comme Event::Read, puis de faire wait() sur tous à la fois, PHP choisissant en dessous le meilleur mécanisme de l'OS : epoll sur Linux, kqueue sur macOS et BSD, WSAPoll sur Windows, les event ports ou le simple poll ailleurs. Jusqu'ici, la réponse intégrée était stream_select(), qui hérite des plafonds de montée en charge de l'antique syscall select(). Soyons clairs sur le périmètre : c'est une primitive d'attente, pas de scheduler, pas de boucle d'événements, pas de mot-clé async. Mais des projets comme Amp et ReactPHP, qui aujourd'hui s'appuient sur stream_select() ou demandent à ton équipe ops d'installer une extension supplémentaire, obtiennent une fondation native dans chaque build PHP par défaut. Et oui, wait() prend une Duration pour son timeout, zéro pour une vérification non bloquante, null pour bloquer jusqu'à ce qu'il se passe quelque chose. Les nouvelles pièces s'emboîtent déjà.
Maintenant, le contrepoint honnête. La syntaxe, c'est ce qui change tes diffs dès le premier jour, et l'application partielle va remodeler le code quotidien bien plus visiblement que n'importe quel objet Duration. Je le concède, et j'ajoute les réserves à connaître : les arguments que tu fournis en construisant une partielle sont évalués sur place, au moment de la création, donc une lecture de config embarquée dans une partielle reste figée, alors que la même lecture dans une fonction fléchée se rejoue à chaque appel. Et une partielle est une closure anonyme toute neuve ; demande à la réflexion qui elle est et elle ne te dira rien de la fonction qu'elle enveloppe, tandis que strlen(...) garde son identité, attributs compris. Pourquoi je classe quand même le travail de bibliothèque plus haut ? Parce que tu as toujours pu simuler la curryfication avec fn() et un peu de discipline. Aucun package composer ne peut faire de Duration le type d'unité sur lequel les drivers PDO, les clients HTTP et ton propre code s'accordent tous, et aucun ne peut glisser epoll dans le runtime par défaut. Seul le cœur peut frapper la monnaie d'un vocabulaire commun.
Avant de migrer, budgète le ménage. Les défauts de session deviennent plus stricts d'entrée de jeu : session.use_strict_mode, cookie_httponly et une valeur SameSite à Lax forment désormais la base, ce qui est le bon choix mais surprendra les flux de connexion cross-site et tout JavaScript qui lit le cookie de session. Faire un return depuis un bloc finally est déprécié, tout comme renvoyer des valeurs depuis __construct() et __destruct(). spl_object_hash() est sur le départ ; spl_object_id() le remplace mais rend un int au lieu d'une chaîne de 32 caractères, donc grep le code qui stocke ou compare ces hashes. Les alias hérités comme is_double(), plus strcoll(), metaphone() et la coercition d'objet en tableau rejoignent la liste des dépréciations, les identifiants let, is et readonly deviennent réservés pour les noms de classes et de fonctions, et la famille trim() supprime désormais les caractères form-feed par défaut. PHPCompatibility, Rector et une baseline PHPStan transforment tout ça en checklist plutôt qu'en crise.
Voilà où j'attends sincèrement qu'on me contredise. Chacun de ces ajouts recoupe quelque chose que l'userland avait déjà construit : des objets temporels façon Carbon, des enums de tri de framework, des helpers clamp faits maison, ext-uv. Un camp dit que le cœur, en absorbant ce territoire, nous donne enfin une convention au lieu de six. L'autre dit qu'il en ajoute juste une septième, et que la douleur d'interopérabilité entre Time\Duration et DateInterval, ou entre SortDirection et ce que ton ORM a inventé en 2019, survivra au bénéfice. Toi, tu te ranges où, et que devrait standardiser le cœur ensuite : un type money, un vrai objet URI, ou rien du tout pendant un moment ?




Commentaires
Pas encore de commentaire — écris le premier.
Lance la discussion
Pas de compte ni de mot de passe — saisis simplement ton adresse e-mail et nous t’envoyons un lien de connexion à usage unique. Première visite ? Tout se met en place automatiquement.
Ton évaluation sera appliquée automatiquement après ta connexion.
Vérifie ta boîte mail
Nous avons envoyé un lien de connexion à …. Ouvre-le sur cet appareil — cet onglet te connectera automatiquement.
Rien reçu ? Vérifiez le dossier spam — et marquez le message « Non spam » pour qu'il arrive directement la prochaine fois.