# OPcache explicado: a cache de bytecode do PHP

> OPcache explicado: como funciona a cache de bytecode do PHP, que definições contam, por que razão deve ser limpa após atualizações e como a proteger.

Fonte: https://phpsos.de/pt/php/opcache/  
Atualizado em: 25/10/2026  
Prestador: PHP SOS, Assistência de emergência PHP e segurança de servidores. Ajuda imediata por WhatsApp: https://wa.me/491736494914?text=Ol%C3%A1%2C%20PHP%20SOS%2C%20precisamos%20de%20ajuda%20com%20o%20nosso%20servidor%20PHP.%20Empresa%3A%20%E2%80%A6%20Site%3A%20%E2%80%A6

**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](https://phpsos.de/pt/php/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:

```ini
; 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:

```ini
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
<?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](https://phpsos.de/pt/php/jit-und-performance/).

## 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:

1. **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](https://phpsos.de/pt/php2shell/php-fpm-neustart/).
2. **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.
3. **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_permission` e `opcache.restrict_api`. Um diretório para `opcache.file_cache` só pode ser gravável pelo utilizador do PHP.

> **Dica:**
> 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](https://phpsos.de/pt/leistungen/server-haertung/), definimos pools separados, `restrict_api` e 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.

## Fontes

- [Manual do PHP: OPcache](https://www.php.net/manual/en/book.opcache.php)
- [Manual do PHP: configuração do OPcache](https://www.php.net/manual/en/opcache.configuration.php)
- [Manual do PHP: instalação do OPcache](https://www.php.net/manual/en/opcache.installation.php)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
