OPcache et JIT

OPcache fonctionne d'emblée avec OxPHP. Tous les threads worker PHP partagent un même segment de mémoire OPcache. Les scripts sont compilés une seule fois à la première exécution, puis servis depuis le cache par chaque worker ensuite. Aucune configuration particulière n'est nécessaire pour activer ce partage.

Fonctionnement d'OPcache avec OxPHP

OxPHP s'enregistre comme un SAPI nommé, et OPcache le traite exactement comme les autres SAPI serveur. Les caractéristiques principales sont :

  • Cache partagé entre les workers : tous les threads worker PHP utilisent le même cache d'opcodes compilés. Un worker compile un fichier ; tous les workers en profitent.
  • Aucune compilation par requête : après la première requête pour chaque script, les requêtes suivantes sautent entièrement l'étape d'analyse et de compilation.
  • opcache.enable_cli n'a aucun effet sur OxPHP. Ce réglage ne s'applique qu'aux SAPI nommés cli et phpdbg. OxPHP s'enregistre sous le nom de SAPI cli-server, si bien qu'OPcache est contrôlé uniquement via opcache.enable. Le réglage opcache.enable_cli est utile si vous exécutez PHP CLI dans le même conteneur (par exemple, pour des migrations ou des commandes Artisan). L'image officielle OxPHP embarque PHP CLI aux côtés du binaire serveur, vous pouvez donc définir opcache.enable_cli=1 si vos scripts CLI tirent parti de la mise en cache.

Pour activer OPcache, au minimum :

ini
[opcache] opcache.enable=1
Note

L'image Docker officielle d'OxPHP est basée sur php:*-zts-alpine, qui compile OPcache statiquement dans le binaire PHP. N'ajoutez PAS zend_extension=opcache à votre fichier INI. L'extension est déjà chargée, et ajouter cette ligne provoquera un avertissement à chaque démarrage de PHP. Seule la section de configuration [opcache] est nécessaire.

Réglages de production recommandés

Ces réglages sont optimisés pour les déploiements de conteneurs en production, où les fichiers PHP ne changent pas à l'exécution. Désactivez la validation des horodatages et préchargez les fichiers compilés au démarrage pour un débit maximal.

ini
[opcache] opcache.enable=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.validate_timestamps=0 opcache.revalidate_freq=0 opcache.file_update_protection=0 opcache.jit_buffer_size=64M opcache.jit=tracing
Réglage Valeur recommandée Description
memory_consumption 128 Mémoire partagée en Mo pour les scripts compilés. Augmentez-la si opcache_get_status() indique peu de mémoire libre.
interned_strings_buffer 16 Mémoire en Mo pour les chaînes internalisées partagées entre tous les workers.
max_accelerated_files 10000 Nombre maximal de scripts mis en cache. Définissez cette valeur au-dessus du nombre total de vos fichiers .php.
validate_timestamps 0 Lorsque la valeur est 0, OPcache ne vérifie jamais les changements sur le système de fichiers. Redémarrez le conteneur ou appelez opcache_reset() pour prendre en compte les modifications de code.
revalidate_freq 0 Secondes entre deux vérifications du système de fichiers. Sans effet lorsque validate_timestamps=0.
file_update_protection 0 Secondes après la modification d'un fichier avant qu'il ne soit éligible à la mise en cache. Réglez à 0 pour le mettre en cache immédiatement au démarrage.

Réglages de développement

En développement, activez la validation des horodatages pour que les modifications de code prennent effet sans redémarrer le conteneur. Désactivez le JIT pour obtenir des traces d'appels plus claires lors du débogage.

ini
[opcache] opcache.enable=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.validate_timestamps=1 opcache.revalidate_freq=2 opcache.jit_buffer_size=0 opcache.jit=disable

Avec validate_timestamps=1, OPcache vérifie les dates de modification des fichiers toutes les revalidate_freq secondes. Cela ajoute une légère surcharge par requête, mais vous permet de modifier des fichiers PHP et de voir les changements dès la requête suivante.

C'est la stratégie de rechargement recommandée en mode développement pour OxPHP. OPcache effectue la vérification en ligne à chaque include, de sorte que les modifications de code sont prises en compte à la requête suivante, sans redémarrage du conteneur ni démon externe de surveillance de fichiers. Utilisez revalidate_freq=0 pour un stat à chaque include (précision maximale, un peu plus d'E/S), ou revalidate_freq=2 pour amortir le coût du stat. La valeur par défaut présentée ci-dessus offre un bon compromis, surtout si votre DOCUMENT_ROOT se trouve sur un bind-mount lent (Docker sur macOS/Windows).

Ce qui n'est PAS rechargé par validate_timestamps

Quelques catégories de changements exigent toujours un redémarrage du conteneur (ou un recyclage du worker), même avec validate_timestamps=1 :

  • Les fichiers préchargés (opcache.preload) sont liés au serveur au démarrage et ne sont jamais revalidés. Si vous modifiez un fichier préchargé, redémarrez le conteneur.
  • L'état de bootstrap du mode worker — en mode worker, l'autoloader, le conteneur d'injection de dépendances et tous les objets construits dans la portée externe résident dans la mémoire du worker. OPcache recompilera les fichiers de classe modifiés, mais le worker ne réexécutera pas son bootstrap. Pour les boucles worker en développement, appelez Worker::scheduleExit() à la fin de chaque requête (par exemple derrière un indicateur d'environnement OXPHP_DEV) pour recycler le worker, ce qui réexécute la portée externe et prend en compte tous les changements.
  • Les caches au niveau du framework — conteneur Symfony compilé, cache de routes/config/vues de Laravel, classmap optimisée de Composer. Ce sont des fichiers .php qu'OPcache revalide, mais les valeurs qu'ils contiennent référencent des chemins de classe ou des identifiants de conteneur périmés. Exécutez la commande cache:clear du framework ; OPcache seul ne suffit pas.
  • Les fichiers non-PHP.env, composer.json, config YAML/JSON, fichiers de templates compilés en dehors d'OPcache. OPcache ne suit que les fichiers qu'il a compilés ; tout le reste nécessite un redémarrage.

Compilation JIT

Le compilateur JIT d'OPcache traduit les opcodes PHP en code machine natif à l'exécution. Utilisez le mode tracing pour la meilleure optimisation :

ini
opcache.jit=tracing opcache.jit_buffer_size=64M

Le JIT apporte le plus de bénéfice au code PHP limité par le CPU : boucles à forte charge mathématique, traitement de chaînes, manipulation d'images et rendu de templates. Pour les applications limitées par les E/S, qui passent l'essentiel de leur temps à attendre des requêtes de base de données ou des appels d'API externes, l'amélioration est minime.

Pour désactiver le JIT :

ini
opcache.jit=disable opcache.jit_buffer_size=0

Préchargement

Le préchargement d'OPcache compile et met en cache les fichiers PHP au démarrage du serveur, avant que la moindre requête ne soit traitée. Cela élimine entièrement le coût de compilation à la première requête et rend les classes et les fonctions disponibles globalement, sans aucun coût de require ou d'autoload.

Configurez le préchargement dans votre fichier INI :

ini
opcache.preload=/var/www/html/preload.php opcache.preload_user=www-data

Créez un script preload.php qui charge vos fichiers les plus fréquemment utilisés :

preload.php
<?php // preload.php — runs once at server startup require __DIR__ . '/vendor/autoload.php'; // Preload framework core files $files = glob(__DIR__ . '/vendor/symfony/http-kernel/**.php'); foreach ($files as $file) { opcache_compile_file($file); } // Preload hot application paths opcache_compile_file(__DIR__ . '/src/Controller/ApiController.php'); opcache_compile_file(__DIR__ . '/src/Service/UserService.php');
Note

Les classes et fonctions préchargées sont disponibles en permanence pour toutes les requêtes. Elles ne peuvent pas être modifiées sans redémarrer le serveur.

Mode worker et préchargement

Si vous utilisez le mode worker, votre application est déjà initialisée une seule fois : l'autoloader, la configuration et les connexions à la base de données persistent entre les requêtes. Le préchargement d'OPcache complète ce mécanisme en éliminant le coût de compilation des opcodes, mais il ne remplace pas l'initialisation de l'application. Les deux mécanismes fonctionnent indépendamment et peuvent être utilisés ensemble.

Application de la configuration PHP

OxPHP lit la configuration PHP depuis le répertoire standard conf.d. Utilisez un volume Docker ou une instruction COPY pour fournir votre fichier INI personnalisé.

bash
docker run -p 80:80 \ -v ./custom.ini:/usr/local/etc/php/conf.d/custom.ini:ro \ ghcr.io/oxphp/oxphp:0.10.0

Surveillance de l'état du cache

Inspectez l'état d'OPcache en direct depuis PHP pour vérifier qu'il fonctionne :

php
<?php $status = opcache_get_status(); echo "Cached scripts: " . $status['opcache_statistics']['num_cached_scripts'] . "\n"; echo "Cache hits: " . $status['opcache_statistics']['hits'] . "\n"; echo "Cache misses: " . $status['opcache_statistics']['misses'] . "\n"; echo "Free memory: " . $status['memory_usage']['free_memory'] . " bytes\n";

Si free_memory est constamment faible, augmentez opcache.memory_consumption.

Voir aussi