Preloading

À partir de PHP 7.4.0, PHP peut ĂȘtre configurĂ© pour prĂ©charger des scripts dans l'opcache lorsque le moteur dĂ©marre. Toutes les fonctions, classes, interfaces ou traits (mais pas les constantes) de ces fichiers deviendront alors disponibles globalement pour toutes les requĂȘtes sans avoir besoin d'ĂȘtre explicitement incluses. Cela Ă©change la commoditĂ© et les performances (car le code est toujours disponible) contre l'utilisation de la mĂ©moire de base. Cela nĂ©cessite Ă©galement de redĂ©marrer le processus PHP pour effacer les scripts prĂ©chargĂ©s, ce qui signifie que cette fonctionnalitĂ© n'est pratique qu'en production, pas dans un environnement de dĂ©veloppement.

Il est Ă  noter que le compromis optimal entre les performances et la mĂ©moire peut varier en fonction de l'application. "Tout prĂ©charger" peut ĂȘtre la stratĂ©gie la plus simple, mais pas nĂ©cessairement la meilleure. De plus, le prĂ©chargement n'est utile que lorsqu'il y a un processus persistant d'une requĂȘte Ă  une autre. Cela signifie que bien que cela puisse fonctionner dans un script CLI si l'opcache est activĂ©, c'est gĂ©nĂ©ralement inutile. L'exception est lors de l'utilisation du prĂ©chargement sur les bibliothĂšques FFI.

Note: Le préchargement n'est pas supporté sur Windows.

La configuration du préchargement implique deux étapes, et nécessite que l'opcache soit activé. Tout d'abord, définir la valeur opcache.preload dans php.ini :

opcache.preload=preload.php

preload.php est un fichier arbitraire qui sera exécuté une fois au démarrage du serveur (PHP-FPM, mod_php, etc.) et chargera du code en mémoire persistante. Dans les serveurs qui démarrent en tant que root avant de passer à un utilisateur systÚme non privilégié, ou si PHP est exécuté en tant que root (non recommandé), la valeur opcache.preload_user peut spécifier l'utilisateur systÚme pour exécuter le préchargement. L'exécution du préchargement en tant que root n'est pas autorisée par défaut. Définir opcache.preload_user=root pour l'autoriser explicitement.

Dans le script preload.php, tout fichier rĂ©fĂ©rencĂ© par include, include_once, require, require_once, ou opcache_compile_file() va ĂȘtre analysĂ© et stockĂ© dans la mĂ©moire persistante. Dans l'exemple suivant, tous les fichiers .php du rĂ©pertoire src seront prĂ©chargĂ©s, sauf s'ils sont un fichier Test.

<?php
$directory
= new RecursiveDirectoryIterator(__DIR__ . '/src');
$fullTree = new RecursiveIteratorIterator($directory);
$phpFiles = new RegexIterator($fullTree, '/.+((?<!Test)+\.php$)/i', RecursiveRegexIterator::GET_MATCH);

foreach (
$phpFiles as $key => $file) {
require_once
$file[0];
}
?>

include et opcache_compile_file() fonctionneront tous les deux, mais ont des implications différentes pour la façon dont le code est géré.

  • include va exĂ©cuter le code du fichier, tandis que opcache_compile_file() ne le fera pas. Cela signifie que seul le premier supporte la dĂ©claration conditionnelle (les fonctions dĂ©clarĂ©es Ă  l'intĂ©rieur d'un bloc if).
  • Parce que include va exĂ©cuter le code, les fichiers inclus de maniĂšre imbriquĂ©e seront Ă©galement analysĂ©s et leurs dĂ©clarations prĂ©chargĂ©es.
  • opcache_compile_file() peut charger des fichiers dans n'importe quel ordre. C'est-Ă -dire que si a.php dĂ©finit la classe A et b.php dĂ©finit la classe B qui Ă©tend A, alors opcache_compile_file() peut charger ces deux fichiers dans n'importe quel ordre. Lors de l'utilisation de include, cependant, a.php doit ĂȘtre inclus en premier.
  • Dans les deux cas, si un script ultĂ©rieur inclut un fichier qui a dĂ©jĂ  Ă©tĂ© prĂ©chargĂ©, alors son contenu sera toujours exĂ©cutĂ©, mais les symboles qu'il dĂ©finit ne seront pas redĂ©finis. L'utilisation de include_once n'empĂȘchera pas le fichier d'ĂȘtre inclus une seconde fois. Il peut ĂȘtre nĂ©cessaire de charger un fichier Ă  nouveau pour inclure les constantes globales dĂ©finies en lui, car elles ne sont pas gĂ©rĂ©es par le prĂ©chargement.
Quelle approche est la meilleure dépend donc du comportement souhaité. Avec du code qui utiliserait autrement un chargement automatique, opcache_compile_file() permet une plus grande flexibilité. Avec du code qui serait autrement chargé manuellement, include sera plus robuste.
add a note

User Contributed Notes 2 notes

up
6
postmaster at greg0ire dot fr ¶
3 years ago
PHP 8.1 comes with an inheritance cache that partially overlaps with what the preloading already does. If you enabled preloading on lower versions then migrated to PHP 8.1, you might want to turn off preloading and see if that comes with a performance penalty or not.
up
1
postmaster at greg0ire dot fr ¶
3 years ago
There are caveats when enabling preloading, one of them being that it should be enabled via a php.ini file. Enabling it with a php-fpm pool configuration won't work, for instance, since preloading is global and not per-pool. To make sure that you successfully enabled preloading, you should check for a preload_statistics key in the output of opcache_get_status(). There should already be an opcache_statistics key, but that's something else entirely.