Fiquei curioso e verifiquei o link de Adam Backstrom para Tech Your Universe . Este artigo descreve um dos motivos que exigem que deve ser usado em vez de require_once. No entanto, suas reivindicações não se sustentaram na minha análise. Eu estaria interessado em ver onde eu posso ter analisado mal a solução. Eu usei o PHP 5.2.0 para comparações.
Comecei criando 100 arquivos de cabeçalho que usavam require_once para incluir outro arquivo de cabeçalho. Cada um desses arquivos se parecia com:
<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";
?>
Eu os criei usando um hack rápido do Bash:
for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
echo "<?php
// $i" > $i
cat helper.php >> $i;
done
Dessa forma, eu poderia facilmente trocar entre usar require_once e exigir ao incluir os arquivos de cabeçalho. Eu criei um app.php para carregar os cem arquivos. Parecia:
<?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);
?>
Comparei os cabeçalhos require_once com os headers require que usavam um arquivo de cabeçalho parecido com:
<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
require "../phpperf/common_hdr.php";
define('CommonHdr', 1);
}
?>
Não encontrei muita diferença ao executar isso com require vs. require_once. De fato, meus testes iniciais pareciam sugerir que require_once era um pouco mais rápido, mas eu não acredito necessariamente nisso. Repeti o experimento com 10000 arquivos de entrada. Aqui eu vi uma diferença consistente. Eu executei o teste várias vezes, os resultados estão próximos, mas usando require_once usa, em média, 30,8 jiffies do usuário e 72,6 jiffies do sistema; o uso requer usos em média de 39,4 instantes do usuário e 72,0 instantes do sistema. Portanto, parece que a carga é um pouco menor usando require_once. No entanto, o tempo do relógio de parede é ligeiramente aumentado. As 10.000 chamadas require_once usam 10,15 segundos para concluir, em média, e 10.000 exigem chamadas usam 9,84 segundos, em média.
O próximo passo é analisar essas diferenças. Eu usei o strace para analisar as chamadas do sistema que estão sendo feitas.
Antes de abrir um arquivo a partir de require_once, são feitas as seguintes chamadas do sistema:
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
Isso contrasta com exige:
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 implica que require_once deve fazer mais chamadas lstat64. No entanto, ambos fazem o mesmo número de chamadas lstat64. Possivelmente, a diferença é que não estou executando o APC para otimizar o código acima. No entanto, a seguir, comparei a saída do strace para todas as execuções:
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190709 strace_1000r.out
210707 strace_1000ro.out
401416 total
Efetivamente, existem aproximadamente mais duas chamadas do sistema por arquivo de cabeçalho ao usar require_once. Uma diferença é que require_once possui uma chamada adicional para a função time ():
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20009
strace_1000ro.out:30008
A outra chamada do sistema é getcwd ():
[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out
strace_1000r.out:5
strace_1000ro.out:10004
Isso é chamado porque eu decidi o caminho relativo mencionado nos arquivos hdrXXX. Se eu fizer disso uma referência absoluta, a única diferença é a chamada de tempo adicional (NULL) feita no código:
[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
Isso parece implicar que você pode reduzir o número de chamadas do sistema usando caminhos absolutos em vez de caminhos relativos. A única diferença fora disso são as chamadas de tempo (NULL) que parecem ser usadas para instrumentar o código para comparar o que é mais rápido.
Outra observação é que o pacote de otimização da APC tem uma opção chamada "apc.include_once_override", que afirma que reduz o número de chamadas do sistema feitas pelas chamadas require_once e include_once (consulte a documentação do PHP ).