PHP apprend (enfin) à se souvenir. Retour d’expérience complet et décryptage des conférences majeures du Forum PHP 2026.
Je reviens du Forum PHP 2026 organisé par l’AFUP avec pas mal de notes. En les relisant ce week-end, je me suis rendu compte que plusieurs conférences tournaient autour du même sujet sans jamais le nommer : la mémoire.
PHP a toujours fonctionné en repartant de zéro à chaque requête. On boote, on répond, on jette tout. C’est ce qui le rend si robuste, et c’est aussi pour ça qu’on a fini par empiler autour de nos applications des crons, des consumers Messenger, des superviseurs et un Redis qui sert souvent de rustine.
Cette année, on sentait l’écosystème vouloir récupérer un peu de cette mémoire. Dans le runtime avec FrankenPHP, dans les connexions longues avec Mercure. Et plus largement dans nos pratiques : savoir ce qu’on embarque comme dépendances, se rappeler qui les maintient, et arrêter de traîner certaines vieilles erreurs du langage. Voici un petit tour de ce que j’ai vu.
FrankenPHP en production chez Matawan
J’ai beaucoup aimé le retour d’expérience de Kevin, tech lead chez Matawan. Ils éditent un SaaS de billettique pour les transports en commun, basé sur les frameworks Symfony et API Platform. Ils ont migré vers FrankenPHP en deux temps.
D’abord en mode classique : Ils ont simplement remplacé leur image PHP-FPM + Nginx, sans toucher au code. Ça leur a pris une journée, surtout pour réaligner la configuration PHP. En production, la latence moyenne a été divisée par trois environ et les pics à 700 ms ont disparu. Pour un changement d’image Docker, difficile de faire mieux.
Ensuite le mode worker : Où le kernel Symfony reste charged entre deux requêtes. Sur leur benchmark (une API de liste de passagers, sans cache), le P95 est passé de 3,4 s à 112 ms, et la latence minimale de 263 ms à 44 ms.
Sauf qu’en jouant avec Postman, Kevin est tombé sur un comportement bizarre : la même liste revenait, que le filtre validity soit à true ou à false. Un bundle maison activait un filtre Doctrine en fonction de la requête, et en mode worker ce filtre restait actif pour la requête d’après. Ça se corrige avec ResetInterface, mais aucun outil ne l’avait détecté (ni les tests, ni PHPStan, ni Rector). Phanalist a bien une règle sur le sujet, mais elle sort plus de 10 000 erreurs sur leur src/.
Focus sur Igor : l’assistant statique contre la pollution de mémoire
Du coup, il a écrit Igor (l’assistant de Frankenstein, forcément), un linter en Go qui s’installe facilement avec Composer. Il cherche les propriétés modifiées dans les services, les static dans les closures, les __destruct() qui ne seront jamais appelés, les reset() incomplets ou les exit(). Il analyse aussi le dossier vendor/, puisque c’est là que leur bug se cachait.
composer require --dev igor-php/igor-php
vendor/bin/igor-php .
La démo m’a convaincu de le lancer sur mes projets avant d’activer le worker mode. Un date_default_timezone_set() ou un __destruct() oublié dans un coin suffit à mettre toutes les requêtes suivantes à l’heure de New York.
Les background workers de Nicolas Grekas
Nicolas Grekas est parti dans une autre direction. Pour lui, le gain du mode worker HTTP est réel mais limité : sur une vraie application, le boot du container représente autour de 10 % du temps de réponse. Ce qui l’intéresse dans FrankenPHP, c’est que le binaire Go sait déjà lancer des threads PHP, les surveiller et les relancer quand ils plantent. Autant s’en servir pour autre chose que servir des pages.
Il travaille dessus depuis mars. Une quinzaine de PR sont déjà mergées et trois sont encore en discussion, donc les noms d’API peuvent encore bouger. L’idée est de déclarer des workers de fond directement dans le Caddyfile :
php_server {
worker public/index.php
worker bin/console background
}
Ces workers ne se lancent jamais depuis PHP, et Nicolas y tient. PHP est invité dans le binaire, il ne possède pas ses threads, et une requête ne devrait pas pouvoir créer quelque chose qui lui survit.
Ils écrivent dans ce qu’il appelle un « tableau blanc », une mémoire partagée gérée par le process Go. Pour une clé donnée, un seul worker a le droit d’écrire, ce qui évite les histoires de verrous qu’on connaît avec APCu.
Son exemple avec Redis Sentinel parlera à ceux qui l’ont en prod. Aujourd’hui, chaque requête demande d’abord à la sentinelle où se trouve le master, puis s’y connecte. Avec un worker abonné en permanence à la sentinelle, la requête n’a plus qu’à lire l’adresse en mémoire. Ce worker peut être écrit en async avec AMPHP, mais ça reste cantonné à quelques briques d’infra que la communauté pourra écrire une fois pour toutes. Notre code métier, lui, ne change pas.
Il a aussi pensé aux pannes. Si un worker plante, la dernière valeur connue reste disponible pendant qu’il redémarre. Et le serveur n’accepte du trafic qu’une fois tous les workers prêts, ce qui règle pas mal de soucis d’ordre de démarrage entre conteneurs. À terme, il aimerait que Redis ne serve plus qu’à stocker des données, et plus à compenser les limites du modèle.
Mercure passe enfin en 1.0
Kévin Dunglas a présenté Mercure 1.0. Il aura fallu sept ans pour sortir de la 0.x, même si l’outil tourne en prod depuis longtemps (COP26, UEFA, l’ANTS…).
Pour ceux qui ne connaissent pas : le navigateur s’abonne à des topics avec EventSource, le serveur publie un événement par un simple POST vers le hub, et le hub le pousse aux clients autorisés. Pas de WebSocket, pas de SDK. Mercure gère en plus l’autorisation par JWT, la récupération des messages perdus quand la connexion coupe, et la liste des clients connectés.
Cette version remplace surtout des choix maison par des standards. Le matching des topics passe par URL Pattern du WHATWG (au lieu d’URI Template, qui n’était pas fait pour ça), et les jetons suivent une RFC de la famille OAuth. Les valeurs par défaut ont été durcies, et un mode de compatibilité permet de migrer sans tout casser.
La nouvelle qui m’a le plus surpris, c’est le support natif dans Laravel 13, avec php artisan install:broadcasting --mercure et Laravel Echo. Côté Symfony, API Platform et FrankenPHP, tout est déjà à jour.
Kévin a aussi beaucoup parlé d’intelligence artificielle, et c’est assez logique : les API d’OpenAI et d’Anthropic streament leurs réponses en Server-Sent Events (SSE). Afficher l’avancement d’un agent depuis un worker Messenger (en attente, en recherche, en train d’appeler un outil, puis la réponse token par token) colle parfaitement à Mercure. Il a même montré un prototype qui délègue le streaming d’un serveur MCP à Mercure (à ne pas mettre en prod pour l’instant).
J’ai surtout retenu son argument sur l’architecture : une requête qui dure 50 ms et une connexion qui reste ouverte une heure n’ont pas les mêmes besoins en timeout, en mémoire ou en règles de WAF. Les faire tourner dans le même pool, c’est se compliquer la vie.
Ce que disent 430 000 paquets PHP (Data & Open Source)
Changement de registre avec Jean-François Lépine, l’auteur de PhpMetrics. Il a cloné à peu près tout Packagist (environ 430 000 paquets) et sorti des statistiques sur 90 millions de méthodes. Tous les chiffres sont des médianes, et le PHP d’entreprise n’y est pas, faute d’accès.
On adopte volontiers ce qu’on peut utiliser seul dans son coin, comme les arguments nommés. Dès qu’une fonctionnalité demande de se mettre d’accord avec l’équipe, elle reste dans les cartons.
Le chiffre qui fait le plus peur : un paquet sur huit dépend d’un paquet abandonné, souvent sans que personne le sache parce que la dépendance est indirecte. Il a terminé en nous invitant à lancer un composer show, à remercier les mainteneurs dont on dépend, voire à les sponsoriser.
Cyber Resilience Act (CRA) : quelles obligations pour le dev PHP ?
Ça tombait bien, parce que la conférence de Rachel Foucard (CTO de W6 et compliance officer pour TYPO3) parlait justement de savoir ce qu’on embarque. Le Cyber Resilience Act (CRA) rend les fabricants de produits numériques responsables de leur sécurité dès qu’ils vendent sur le marché européen.
Le calendrier se resserre. Depuis le 11 septembre 2026, les fabricants doivent signaler à l’ENISA les vulnérabilités activement exploitées, avec une première alerte sous 24 h. La conformité complète, marquage CE compris, est attendue pour la fin d’année 2027.
Rachel a insisté sur un point : l’argument « c’est du SaaS, donc on n’est pas concernés » ne tient pas toujours. Une application mobile qu’on installe est un produit, et un backend sans lequel un objet connecté ne fonctionne pas fait partie du produit. Il faut regarder au cas par cas.
Pour les développeurs, la responsabilité juridique reste à l’entreprise. En revanche, la conformité se prouve avec des traces concrètes : des SBOM (Software Bill of Materials) générés à chaque livraison, des scans de vulnérabilités, et un historique des correctifs. Côté PHP, cyclonedx/cyclonedx-php-composer et composer audit permettent déjà d’en faire une bonne partie dans la CI/CD.
Breaking changes : Gina Banyard veut qu’on ose casser des choses
Gina Banyard défend l’idée que PHP devrait accepter plus de ruptures de compatibilité pour se débarrasser de ses comportements absurdes.
Elle a commencé loin du code, avec des ruptures dans le monde réel. La Suède est passée à la conduite à droite en une nuit de 1967. Le Japon vit toujours avec deux fréquences électriques (50 Hz à l’est, 60 Hz à l’ouest), et après Fukushima l’ouest n’a pas pu envoyer assez de courant à l’est. Et puis il y a le Boeing 737 MAX : pour éviter de reformer les pilotes, Boeing a ajouté le MCAS, une sorte de grosse couche de compatibilité. Après deux crashs, la formation a été imposée quand même.
Elle a aussi rappelé que PHP ne suit pas vraiment SemVer, puisque chaque version mineure casse quelque chose depuis PHP 4. Et avec la loi de Hyrum, même un message d’erreur finit par devenir un comportement dont quelqu’un dépend.
Sa liste de candidats à la suppression parlera à tout le monde :
- Comparer un tableau avec un entier,
- Les variables variables,
uniqid()qui ne garantit pas l’unicité,unserialize()qui peut renvoyer un__PHP_Incomplete_Classau lieu de lever une exception,- Le fallback des fonctions dans un namespace (qui marche pour
strlen()mais pas pournew stdClass).
Elle a fini en rappelant que la mailing list internals est ouverte à tous. Sur ce genre de RFC, ceux qui sont contre se manifestent toujours, ceux qui sont pour beaucoup moins. Si on veut un PHP plus propre, il faut aussi le dire.
Partager ses skills IA (Claude Code) en équipe chez Kizeo
Dernier sujet, plus organisationnel. Chez Kizeo, chaque développeur s’était fait ses propres skills Claude Code dans son coin, et plusieurs avaient écrit chacun leur skill de commit. Le problème est devenu visible côté QA : les devs se sont mis à générer des cahiers de test, mais l’un les mettait dans Notion, l’autre en commentaire Jira, et un troisième dans un sous-ticket.
Ils ont monté une communauté de pratique, ouverte aux devs comme au produit, à la QA et à l’infra. Ils ont commencé par recenser ce que chacun avait fait, puis créé un dépôt commun et fixé quelques règles de contribution : nettoyer les infos personnelles, documenter les conventions dans un fichier AGENTS.md. Ils ont même voté pour passer tous les skills en anglais. Le tout est distribué sous forme de plugins internes, découpés par public pour que le PO n’ait pas à charger les skills de CI.
Ils ont intégré le plugin à leur Definition of Done (DoD) : le cahier de test généré par le skill devient le format attendu, et la QA reçoit enfin toujours la même chose.
Jean-François Lépine notait d’ailleurs qu’environ 4 000 dépôts PHP contiennent déjà un commit signé par un agent IA, alors que le premier date de mars 2025. Le sujet ne va pas disparaître.
Et maintenant ?
Je ne crois pas que PHP soit en train de renoncer à son modèle. Le code métier reste synchrone et sans état. Ce qui change, c’est qu’on peut enfin garder en mémoire ce qui doit durer, dans des briques bien délimitées, sans monter toute une infra à côte.
De mon côté, voici ce que je compte tester dans les semaines qui viennent :
- Lancer Igor sur nos projets avant d’essayer le mode worker ;
- Faire le tri dans nos dépendances avec
composer showet auditer la sécurité ; - Regrouper mes skills Claude Code dans un dépôt d’équipe avec un fichier
AGENTS.md.
Comme le disait Jean-François Lépine, contribuer à un paquet maintenu par une seule personne, c’est doubler son équipe. Rendez-vous l’an prochain au Forum PHP et d’ici là, voici le lien vers le programme et les thèmes abordés cette année.