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.
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 :
| Directive | Valeur de production courante | Rôle |
|---|---|---|
| opcache.enable | 1 | Active le cache d'opcodes |
| opcache.memory_consumption | 256 à 512 Mo | Taille du segment mémoire partagé |
| opcache.interned_strings_buffer | 16 à 32 Mo | Mémoire pour les chaînes internées |
| opcache.max_accelerated_files | 30 000 à 33 000 | Nombre maximal de scripts mis en cache |
| opcache.validate_timestamps | 0 en production | Désactive la vérification systématique des fichiers |
| opcache.revalidate_freq | 2 secondes (défaut) | Fréquence de revérification quand les timestamps sont actifs |
| opcache.jit | 1255 (tracing) | Mode du compilateur à la volée |
| opcache.jit_buffer_size | 128 Mo si JIT actif | Mé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.
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.
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.