Je suis devenu curieux et j'ai vérifié le lien d'Adam Backstrom vers Tech Your Universe . Cet article décrit l'une des raisons pour lesquelles require doit être utilisé au lieu de require_once. Cependant, leurs affirmations ne tiennent pas compte de mon analyse. Je serais intéressé de voir où j'ai peut-être mal analysé la solution. J'ai utilisé PHP 5.2.0 pour les comparaisons.
J'ai commencé par créer 100 fichiers d'en-tête qui utilisaient require_once pour inclure un autre fichier d'en-tête. Chacun de ces fichiers ressemblait à quelque chose comme:
<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";
?>
J'ai créé ceux-ci en utilisant un hack rapide Bash:
for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
echo "<?php
// $i" > $i
cat helper.php >> $i;
done
De cette façon, je pourrais facilement permuter entre l'utilisation de require_once et de require lors de l'inclusion des fichiers d'en-tête. J'ai ensuite créé un app.php pour charger les cent fichiers. Cela ressemblait à:
<?php
// Load all of the php hdrs that were created previously
for($i=0; $i < 100; $i++)
{
require_once "/home/fbarnes/phpperf/hdr$i.php";
}
// Read the /proc file system to get some simple stats
$pid = getmypid();
$fp = fopen("/proc/$pid/stat", "r");
$line = fread($fp, 2048);
$array = split(" ", $line);
// Write out the statistics; on RedHat 4.5 with kernel 2.6.9
// 14 is user jiffies; 15 is system jiffies
$cntr = 0;
foreach($array as $elem)
{
$cntr++;
echo "stat[$cntr]: $elem\n";
}
fclose($fp);
?>
J'ai comparé les en-têtes require_once avec des en-têtes require qui utilisaient un fichier d'en-tête ressemblant à:
<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
require "../phpperf/common_hdr.php";
define('CommonHdr', 1);
}
?>
Je n'ai pas trouvé beaucoup de différence lors de l'exécution avec require et require_once. En fait, mes tests initiaux semblaient impliquer que require_once était légèrement plus rapide, mais je ne le crois pas nécessairement. J'ai répété l'expérience avec 10000 fichiers d'entrée. Ici, j'ai vu une différence cohérente. J'ai exécuté le test plusieurs fois, les résultats sont proches mais l'utilisation de require_once utilise en moyenne 30,8 jiffies utilisateur et 72,6 jiffies système; l'utilisation de require utilise en moyenne 39,4 jiffies utilisateur et 72,0 jiffies système. Par conséquent, il semble que la charge soit légèrement inférieure en utilisant require_once. Cependant, l'heure de l'horloge murale est légèrement augmentée. Les 10 000 appels require_once utilisent en moyenne 10,15 secondes et 10 000 appels nécessitent 9,84 secondes en moyenne.
L'étape suivante consiste à examiner ces différences. J'ai utilisé strace pour analyser les appels système en cours.
Avant d'ouvrir un fichier depuis require_once, les appels système suivants sont effectués:
time(NULL) = 1223772434
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
time(NULL) = 1223772434
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3
Cela contraste avec exiger:
time(NULL) = 1223772905
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
time(NULL) = 1223772905
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3
Tech Your Universe implique que require_once devrait faire plus d'appels lstat64. Cependant, ils effectuent tous les deux le même nombre d'appels lstat64. La différence est peut-être que je n'utilise pas APC pour optimiser le code ci-dessus. Cependant, j'ai ensuite comparé la sortie de strace pour toutes les exécutions:
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190709 strace_1000r.out
210707 strace_1000ro.out
401416 total
En fait, il y a environ deux appels système supplémentaires par fichier d'en-tête lors de l'utilisation de require_once. Une différence est que require_once a un appel supplémentaire à la fonction time ():
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20009
strace_1000ro.out:30008
L'autre appel système est getcwd ():
[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out
strace_1000r.out:5
strace_1000ro.out:10004
Ceci est appelé parce que j'ai décidé du chemin relatif référencé dans les fichiers hdrXXX. Si j'en fais une référence absolue, la seule différence est l'appel de temps supplémentaire (NULL) effectué dans le code:
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190705 strace_1000r.out
200705 strace_1000ro.out
391410 total
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20008
strace_1000ro.out:30008
Cela semble impliquer que vous pouvez réduire le nombre d'appels système en utilisant des chemins absolus plutôt que des chemins relatifs. La seule différence en dehors de cela est les appels de temps (NULL) qui semblent être utilisés pour instrumenter le code pour comparer ce qui est plus rapide.
Une autre note est que le package d'optimisation APC a une option appelée "apc.include_once_override" qui prétend réduire le nombre d'appels système effectués par les appels require_once et include_once (voir la documentation PHP ).