Guide

OPcache et performance PHP en production : le guide de configuration 2026

OPcache est le premier levier de performance d'une application PHP en production : sans lui, chaque fichier est relu et recompilé à chaque requête. Ce guide détaille la configuration recommandée en 2026, la gestion du cache lors des déploiements, le JIT tracing de PHP 8.4 et 8.5, le preloading Symfony et le monitoring du hit rate.

Sans OPcache, PHP relit, analyse et compile chaque fichier inclus à chaque requête. Sur une application Symfony ou Laravel, cela représente des milliers d’opérations répétées qui n’apportent aucune valeur métier. OPcache stocke les opcodes compilés en mémoire partagée : une fois configuré correctement, c’est souvent le gain serveur le plus important pour un coût quasi nul, bien avant toute optimisation applicative.

Ce guide couvre la configuration de production en 2026, du dimensionnement mémoire au preloading, en passant par la gestion du cache lors des déploiements et la surveillance du hit rate. Il s’appuie sur les recommandations documentées par les équipes PHP, les hébergeurs et les retours d’exploitation publiés entre 2025 et 2026.

Pourquoi OPcache reste le premier levier de performance PHP

Le cycle d’exécution de PHP sans cache passe par trois étapes coûteuses pour chaque fichier : lecture sur disque, analyse syntaxique, compilation en opcodes. Le moteur Zend exécute ensuite ces opcodes, puis jette le résultat. À l’échelle d’une requête Symfony moyenne, des centaines de fichiers du noyau, des bundles et du vendor subissent ce traitement, identique à chaque fois.

OPcache place les opcodes compilés dans un segment de mémoire partagée persistante entre les requêtes. Le gain n’est pas un pourcentage abstrait : il supprime carrément une phase entière du cycle de vie de chaque requête. Les guides de performance publiés en 2026 pour Laravel et PHP en général le classent systématiquement parmi les premières actions côté serveur, avant toute modification du code applicatif.

Le point important pour un développeur ou un lead technique : ce levier ne demande aucune refactorisation. Il relève de l’infrastructure, se valide en quelques minutes avec les bonnes commandes, et se surveille avec deux ou trois indicateurs stables.

Développeuse PHP configurant un serveur de production avec des métriques de performance à l'écran
OPcache se pilote côté serveur : une configuration php.ini correcte supprime la recompilation systématique des fichiers à chaque requête.

Si l’application tourne encore sur une version vieillissante de PHP, le sujet se connecte directement à la mise en production de PHP 8.5 : la montée de version et la vérification d’OPcache sont deux volets du même chantier d’exploitation.

PHP 8.5 : OPcache intégré par défaut

PHP 8.5 est sorti le 20 novembre 2025. Parmi ses changements structurels, un est passé relativement inaperçu côté développeurs : OPcache n’est plus une extension optionnelle. L’extension est compilée de manière inconditionnelle et ne peut plus être désactivée à la compilation. L’ancien réflexe consistant à vérifier qu’OPcache est installé avant de le configurer devient obsolète sur les nouvelles installations.

Cette intégration ne signifie pas que la configuration est optimale par défaut. Les valeurs par défaut restent prudentes : un buffer de chaînes internées modeste, un nombre de fichiers accélérés limité et un JIT désactivé tant qu’aucun buffer JIT n’est alloué. Autrement dit, PHP 8.5 garantit la présence d’OPcache, pas sa bonne dimension.

Pour les parcs hétérogènes, la démarche diffère selon les versions :

  • PHP 8.3 et 8.4 : vérifier que l'extension zend-opcache est installée et activée, puis appliquer la même base de directives.
  • PHP 8.5 : vérifier les valeurs effectives plutôt que l'installation, car l'extension est garantie mais les défauts restent conservateurs.
  • PHP 8.1 et antérieur : hors support de sécurité ou proche de la fin de vie ; ce chantier doit passer par un audit du parc PHP et son plan de migration avant toute optimisation.

Vérifier et dimensionner la configuration

La vérification passe par deux commandes simples. La première confirme que l’extension est chargée :

php -v
php -m | grep -i zend

La seconde, plus utile, interroge l’état réel du cache. Attention à un piège documenté par plusieurs retours d’exploitation récents : le cache du mode CLI est indépendant du cache de PHP-FPM. Les statistiques lues depuis la ligne de commande décrivent un cache séparé, presque toujours vide en production. Les chiffres qui comptent sont ceux servis par le SAPI web.

Le tableau suivant synthétise les directives qui structurent une configuration de production, avec les valeurs couramment recommandées en 2026 par les documentation d’hébergeurs et les guides d’exploitation :

DirectiveValeur de production couranteRôle
opcache.enable1Active le cache d'opcodes
opcache.memory_consumption256 à 512 MoTaille du segment mémoire partagé
opcache.interned_strings_buffer16 à 32 MoMémoire pour les chaînes internées
opcache.max_accelerated_files30 000 à 33 000Nombre maximal de scripts mis en cache
opcache.validate_timestamps0 en productionDésactive la vérification systématique des fichiers
opcache.revalidate_freq2 secondes (défaut)Fréquence de revérification quand les timestamps sont actifs
opcache.jit1255 (tracing)Mode du compilateur à la volée
opcache.jit_buffer_size128 Mo si JIT actifMémoire dédiée au code natif compilé

Deux directives méritent une mesure avant fixation. La mémoire totale doit couvrir le bytecode de l’application, du vendor et des chaînes internées ; un Symfony complet dépasse fréquemment 128 Mo. Le nombre de fichiers doit excéder le décompte réel des fichiers PHP du projet, vendor inclus, sinon des scripts tournent en cycle entrée et éviction.

Timestamps, déploiements et vidage du cache

La directive validate_timestamps contrôle la cohérence entre le cache et le disque. Quand elle vaut 1, PHP vérifie périodiquement si un fichier a changé, à la fréquence revalidate_freq dont la valeur documentée par défaut est de deux secondes. Cette vérification est raisonnable sur un poste de développement, mais en production elle ajoute des accès système à chaque requête pour un cas qui n’arrive qu’aux déploiements.

La pratique établie consiste donc à positionner validate_timestamps à 0 en production et à rendre chaque déploiement responsable de la cohérence du cache. C’est la condition de validité de l’optimisation : sans mécanisme fiable de vidage, l’ancien et le nouveau code peuvent cohabiter dans le cache.

La méthode recommandée par la documentation d’exploitation et les retours d’incidents est le rechargement gracieux de PHP-FPM, qui vide le cache de tous les workers de manière coordonnée sans interrompre brutalement les requêtes en cours. Trois points de vigilance accompagnent ce choix :

  • opcache_reset() appelé depuis un script ne touche que le processus qui l'exécute : les autres workers servent l'ancien code, ce qui crée un état incohérent pendant les requêtes en vol.
  • Le rechargement doit être intégré à la procédure de mise en production elle-même, idéalement dans le pipeline, juste après la bascule des releases.
  • Avec des déploiements par lien symbolique qui bascule un répertoire current vers une nouvelle release, les vieux chemins restés en mémoire finissent par encombrer le cache : le redémarrage périodique reste nécessaire même sans changement de code.
Administratrice système vérifiant des serveurs dans une baie de datacenter
Le vidage de cache fait partie de la procédure de déploiement : un rechargement gracieux de PHP-FPM garantit la cohérence entre le code livré et le bytecode servi.

Cette étape trouve naturellement sa place dans un pipeline CI/CD de déploiement Symfony, au même titre que les migrations de base de données ou le vidage des caches applicatifs. À l’inverse, les architectures qui gardent PHP en mémoire entre les requêtes, comme le worker mode de FrankenPHP, changent la donne : le cycle de vie des processus et celui du cache doivent y être repensés ensemble.

Le JIT tracing de PHP 8.4 et 8.5

Le compilateur à la volée de PHP a été entièrement réécrit dans PHP 8.4 autour d’un backend basé sur la représentation intermédiaire. La configuration se fait avec la directive opcache.jit, dont le format CRTO compose quatre chiffres : optimisation CPU, allocation de registres, seuil de déclenchement et niveau d’optimisation. La valeur 1255, fréquemment citée dans les guides 2026, correspond au mode tracing avec les réglages les plus agressifs.

La règle d’or pour un site web classique est de mesurer avant d’espérer. Le JIT excelle sur les boucles de calcul intensif. Une application web typique passe son temps dans des entrées-sorties, des appels base de données et l’exécution du framework : sur ce profil, le gain JIT est rarement visible, et une mauvaise configuration peut même dégrader la stabilité. Les retours d’exploitation publiés en 2026 sur des fortes charges soulignent deux pièges réels : les segfaults liés à une sur-optimisation sur du code très dynamique, et les tempêtes d’invalidation de buffer.

La mise en œuvre prudente suit une séquence stricte :

  • Allouer un jit_buffer_size dédié : sans ce buffer, le JIT ne fait littéralement rien, quelle que soit la valeur de opcache.jit.
  • Activer le tracing avec des seuils conservateurs sur un environnement de charge représentatif.
  • Mesurer l'écart sur des scénarios réels, jamais sur un micro-benchmark synthétique, avant d'envisager la production.

Le preloading pour Symfony et les gros frameworks

Le preloading, disponible depuis PHP 7.4, va plus loin que le cache : au démarrage de PHP-FPM, un script déclaré par opcache.preload charge une liste de fichiers dans la mémoire partagée, où ils deviennent disponibles pour toutes les requêtes sans autoload. Symfony génère ce fichier depuis la version 4.4 : après un warmup du cache, le noyau produit un fichier de preloading dans le répertoire var/cache, que la documentation officielle recommande de référencer dans la configuration PHP, avec la directive opcache.preload_user obligatoire.

Trois limites encadrent l’intérêt réel du preloading. D’abord, il ne fonctionne qu’avec PHP-FPM, pas en CLI. Ensuite, il fige les fichiers préchargés : tout changement de code impose un redémarrage de PHP-FPM, ce qui le couple étroitement à la procédure de déploiement décrite plus haut. Enfin, son gain mesuré est modeste sur une application web dont le temps de réponse total domine largement le coût d’autoload : les évaluations publiées estiment ce dernier à une poignée de millisecondes sur une réponse de l’ordre de la seconde.

Le preloading reste néanmoins pertinent sur des architectures à forte densité de workers et des frameworks volumineux, à condition de mesurer l’écart mémoire qu’il introduit. Une bonne hygiène d’exploitation consiste à le traiter comme une optimisation de second niveau : OPcache correctement dimensionné d’abord, preloading ensuite, et jamais les deux sans monitoring.

Monitorer le hit rate en production

Une configuration OPcache se dégrade en silence : une montée de version du framework qui ajoute des fichiers, un vendor qui grossit, une mémoire qui était juste suffisante deviennent insuffisants sans qu’aucune alerte ne se déclenche. Le seul indicateur qui trahit ce glissement est le hit rate, exposé par opcache_get_status().

Les seuils communément admis dans la documentation d’exploitation sont clairs : un hit rate durablement supérieur à 99 % caractérise une configuration saine ; en dessous de 95 %, la mémoire ou le nombre de fichiers est trop faible et des recompilations invisibles consomment des cycles CPU à chaque requête. Au-delà du hit rate, trois signaux complètent le diagnostic : la mémoire gaspillée au-delà d’environ 10 %, un compteur de scripts en cache proche de max_accelerated_files, et les compteurs de redémarrages sur mémoire épuisée qui révèlent des cycles d’éviction passés.

L’automatisation de ce monitoring peut s’appuyer sur des alias de shell et de petits scripts lancés après chaque déploiement pour les équipes qui gèrent leurs serveurs eux-mêmes ; les développeurs qui veulent aller plus loin dans la personnalisation de leur environnement de travail trouveront par exemple un guide anglophone détaillé sur customizing the Bash shell with aliases and environment variables, utile pour industrialiser ces vérifications récurrentes.

Équipe d'ingénieurs analysant ensemble des courbes de performance sur un grand écran de contrôle
Le hit rate, la mémoire utilisée et les raisons de redémarrage d'OPcache se lisent via opcache_get_status() et doivent figurer dans la supervision courante.

Les erreurs de configuration à éviter

Sur la base des incidents d’exploitation documentés ces derniers mois, quelques erreurs reviennent fréquemment et méritent d’être écartées explicitement :

  • Laisser validate_timestamps à 1 en production avec revalidate_freq à sa valeur basse par défaut, ce qui annule une partie du gain en ajoutant des stat() systématiques.
  • Activer opcache.jit sans allouer opcache.jit_buffer_size, une configuration qui affiche un JIT actif tout en ne produisant aucune compilation.
  • Se fier aux statistiques du CLI pour juger la production, alors que les deux caches sont séparés.
  • Déployer sans mécanisme de vidage, laissant l'ancien bytecode servir les nouvelles requêtes jusqu'à un redémarrage imprévu.
  • Sous-dimensionner max_accelerated_files sur les gros projets, provoquant des évictions silencieuses qui érodent le hit rate.
  • Activer le preloading sans redémarrage planifié, et se retrouver avec des classes figées après chaque mise à jour.

L’essentiel tient en une phrase : OPcache est une optimisation d’infrastructure qui exige les mêmes disciplines qu’une mise en production applicative — mesure avant réglage, procédure de déploiement explicite, et supervision continue. Traité ainsi, il reste l’un des rares réglages qui rendent une application PHP plus rapide sans toucher à une seule ligne de code métier.

Questions fréquentes

OPcache apporte-t-il encore un gain avec PHP 8.4 ou 8.5 ?
Oui. Les versions modernes de PHP exécutent le code plus vite, mais sans OPcache chaque fichier inclus reste lu, analysé et compilé en opcodes à chaque requête. Le cache d'opcodes supprime ce travail répété, indépendamment de la version du langage. Même en PHP 8.5, où l'extension est compilée par défaut, les directives doivent être vérifiées et dimensionnées pour l'application réelle.
Quelle valeur donner à opcache.memory_consumption ?
Il n'existe pas de valeur universelle. Une application Symfony ou Laravel avec un vendor conséquent dépasse souvent 128 Mo de bytecode et de chaînes internées. La méthode fiable consiste à partir de 256 Mo, à mesurer la consommation réelle avec opcache_get_status(), puis à augmenter si la mémoire utilisée se rapproche de l'allocation ou si le taux de remplissage déclenche des évictions.
Faut-il activer le JIT en production ?
Le JIT tracing peut aider les workloads de calcul intensif, mais il ne transforme pas les temps de réponse d'une application web classique dont le temps est dominé par les entrées-sorties et le framework. L'approche prudente consiste à l'activer sur un périmètre de test, à mesurer l'écart sur des scénarios réels, puis à décider. Il exige un jit_buffer_size dédié, sans quoi il ne fait rien.
Pourquoi opcache_reset() après un déploiement est-il déconseillé ?
opcache_reset() ne vide le cache que pour le processus qui exécute l'appel. Les autres workers PHP-FPM continuent de servir l'ancien bytecode jusqu'à leur propre réinitialisation, ce qui produit un état incohérent pendant les requêtes en vol. Le redémarrage gracieux de PHP-FPM, par rechargement du service, est la méthode coordonnée qui vide le cache de tous les workers sans couper brutalement les connexions.
Comment surveiller la santé d'OPcache au quotidien ?
Le point d'entrée principal est opcache_get_status(), qui expose le hit rate, la mémoire utilisée et gaspillée, le nombre de scripts mis en cache et les raisons de redémarrage. Un hit rate durablement sous 95 % signale une mémoire ou un nombre de fichiers trop faible. Ces indicateurs peuvent être exportés vers l'outil de supervision existant et consultés après chaque déploiement.