Em resumo: O OPcache é a cache de bytecode integrada do PHP. Segundo o manual, guarda bytecode pré-compilado na memória partilhada, de modo que o PHP não tem de carregar e traduzir os scripts a cada pedido. Faz parte da distribuição desde o PHP 5.5.0. O OPcache torna o PHP mais rápido, mas não substitui uma atualização: depois de um patch do PHP, todos os processos PHP têm de ser reiniciados, não basta limpar a cache.
O que faz exatamente o OPcache?
A cada pedido, o PHP tem de ler um script, decompô-lo e traduzi-lo em opcodes, ou seja, nas instruções para a máquina virtual da Zend Engine. Num CMS com centenas de ficheiros, é muito trabalho que se repete constantemente.
O OPcache guarda o resultado desta tradução na memória partilhada (shared memory). Todos os workers de um serviço PHP-FPM, ou todos os processos Apache com mod_php, acedem a ela. Se um ficheiro não muda, o seu bytecode é reutilizado diretamente.
O OPcache é carregado como extensão Zend, não como extensão normal:
; Linux (caminho consoante o pacote)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
Segundo o manual, o OPcache deve ser carregado antes do Xdebug quando ambos estão ativos.
É importante saber a quem pertence a memória partilhada. No PHP-FPM, é o processo mestre que a cria e todos os workers de todos os pools desse serviço a utilizam. No mod_php, pertence ao processo principal do Apache. Um reinício do serviço esvazia por isso a cache por completo, ao contrário de um único worker novo. Para a linha de comandos não existe memória partilhada entre chamadas, porque cada chamada é um processo próprio; aí o OPcache está desligado por defeito.
Para quem decide, basta uma regra prática: o OPcache faz quase sempre sentido em servidores de produção, mas exige um procedimento claro para implementações e atualizações.
Que definições do OPcache contam?
Os valores seguintes provêm da página de configuração do manual do PHP. A coluna «Alterável» mostra onde uma definição pode ser fixada: INI_SYSTEM apenas no php.ini ou na configuração do servidor, INI_ALL em qualquer lado.
| Diretiva | Por defeito | Alterável | Significado |
|---|---|---|---|
opcache.enable |
1 | INI_ALL | cache ligada ou desligada, em tempo de execução só se pode desligar |
opcache.enable_cli |
0 | INI_SYSTEM | cache para a linha de comandos |
opcache.memory_consumption |
128 | INI_SYSTEM | tamanho da memória partilhada em MB |
opcache.interned_strings_buffer |
8 | INI_SYSTEM | memória para cadeias de carateres partilhadas em MB |
opcache.max_accelerated_files |
10000 | INI_SYSTEM | número máximo de scripts em cache |
opcache.validate_timestamps |
1 | INI_ALL | verifica se os ficheiros foram alterados |
opcache.revalidate_freq |
2 | INI_ALL | intervalo de verificação em segundos, 0 = a cada pedido |
opcache.restrict_api |
vazio | INI_SYSTEM | só permite as funções da API a partir de um caminho |
opcache.validate_permission |
0 | INI_SYSTEM | verifica as permissões dos ficheiros em relação ao utilizador atual |
opcache.validate_root |
0 | INI_SYSTEM | evita colisões de nomes em chroot |
opcache.file_cache |
vazio | INI_SYSTEM | segundo nível de cache no disco |
Uma configuração de produção típica poderia ter este aspeto. Verifique antes os valores com a sua aplicação:
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.restrict_api=/var/www/admin-tools
Quem define opcache.validate_timestamps=0 ganha um pouco de desempenho. Mas então o OPcache deixa de detetar ficheiros alterados e cada implementação precisa de um reset da cache ou de um reinício.
Observar a cache e limpá-la de forma dirigida
O OPcache traz funções próprias, entre elas opcache_get_status(), opcache_get_configuration(), opcache_invalidate() e opcache_reset(). Uma olhadela curta, apenas de leitura, ao nível de ocupação:
<?php
$status = opcache_get_status(false);
if ($status === false) {
exit("OPcache ist nicht aktiv.\n");
}
printf("Gecachte Skripte: %d\n", $status['opcache_statistics']['num_cached_scripts']);
printf("Freier Speicher: %.1f MB\n", $status['memory_usage']['free_memory'] / 1048576);
Em servidores com vários sites, nem todas as aplicações devem poder esvaziar ou ler a cache de todas as outras. É para isso que serve o opcache.restrict_api: só os scripts abaixo do caminho indicado podem chamar as funções da API.
JIT: o compilador de código máquina no OPcache
Desde o PHP 8.0, o OPcache contém um compilador JIT que traduz opcodes em código máquina. Segundo o RFC do JIT, é uma parte quase autónoma do OPcache e guarda o código gerado numa área própria da memória partilhada. É controlado através de opcache.jit e opcache.jit_buffer_size. Desde o PHP 8.4.0, o opcache.jit está por defeito em disable. Quando compensa usar o JIT explica-o o artigo JIT e desempenho no PHP 8.
OPcache e segurança: o que vale depois do PHP2Shell
O OPcache não é uma ferramenta de segurança, mas tem consequências para a segurança. Depois do PHP2Shell, três pontos são importantes:
- Um reset da cache não é uma atualização. O
opcache_reset()só esvazia scripts em cache. O interpretador com as vulnerabilidades CVE-2026-109618 e CVE-2026-109619 permanece na memória até todos os processos serem reiniciados. Como fazê-lo está em Reiniciar o PHP-FPM e todos os workers. - O código injetado pode sobreviver na cache. Se um ficheiro foi manipulado e mais tarde substituído, com a verificação de datas desligada a versão antiga pode continuar a ser executada. Depois de uma limpeza, por isso, faz parte do processo um reinício.
- A memória partilhada precisa de separação. Em servidores com vários clientes ajudam pools PHP-FPM próprios por site, bem como
opcache.validate_permissioneopcache.restrict_api. Um diretório paraopcache.file_cachesó pode ser gravável pelo utilizador do PHP.
Depois de cada atualização, verifique se a hora de arranque dos processos PHP é posterior à atualização. Um OPcache cheio com uma taxa de acertos elevada não prova que o novo interpretador está em execução.
Como ajuda concretamente a PHP SOS?
- Verificar a configuração: Lemos a configuração ativa do OPcache por modo de operação e comparamo-la com a sua aplicação.
- Proteger as implementações: Estabelecemos um procedimento fixo de reset da cache e reinício, para que nenhuma versão antiga do código continue a correr.
- Separar clientes: No âmbito do reforço de servidores, definimos pools separados,
restrict_apie permissões adequadas. - Controlar depois das atualizações: Comprovamos, através das horas de arranque dos processos, que o interpretador atualizado está realmente ativo.
Perguntas frequentes
O OPcache está ativo por defeito?
O OPcache é distribuído com o PHP desde o PHP 5.5.0 e, segundo o manual, funciona com opcache.enable=1 por defeito assim que a extensão está carregada. Se está carregada depende do seu pacote ou alojador. Na linha de comandos, em contrapartida, o OPcache está desligado por defeito (opcache.enable_cli=0).
Porque é que depois de uma implementação ainda vejo o código antigo?
Provavelmente o OPcache só verifica alterações de ficheiros a intervalos ou nunca as verifica. Com opcache.revalidate_freq espera, por defeito, dois segundos; com opcache.validate_timestamps=0, nunca. Nesse caso só ajuda um reset da cache ou um reinício do PHP-FPM ou do Apache.
O opcache_reset() basta depois de uma atualização do PHP?
Não. O opcache_reset() só esvazia a cache de scripts traduzidos. Uma atualização do PHP substitui o próprio interpretador, que está carregado em cada processo em execução. Para isso, todos os processos PHP têm de ser reiniciados.
O JIT está ligado no PHP 8.4?
Segundo o manual, desde o PHP 8.4.0 o opcache.jit está por defeito em disable, enquanto o opcache.jit_buffer_size é de 64M. Antes era o contrário: jit em tracing, buffer a 0. Em ambos os casos, o JIT não está ativo sem uma configuração deliberada.