# A Zend Engine: o coração do PHP

> A Zend Engine explicada: compilador, opcodes, máquina virtual, zval e gestão de memória no núcleo do PHP, as suas versões e o papel nos patches.

Fonte: https://phpsos.de/pt/php/zend-engine/  
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:** A Zend Engine é o núcleo do PHP. Traduz o código PHP em opcodes, executa-os numa máquina virtual e gere nesse processo as variáveis e a memória. Desde o PHP 4 está presente em todas as instalações do PHP. Como as vulnerabilidades do PHP2Shell estão neste núcleo, não ajudam plugins nem atualizações do CMS, mas apenas um PHP atualizado com reinício.

## O que é a Zend Engine?

A Zend Engine é a parte do PHP que faz o trabalho propriamente dito. Tudo o resto, como a ligação ao servidor web ou as extensões para bases de dados, assenta nela. Pode compará-la ao motor de um automóvel: a carroçaria e o equipamento diferem, mas o motor move tudo.

Segundo o manual do PHP, o nome foi formado a partir dos nomes próprios dos criadores, Zeev Suraski e Andi Gutmans. O motor foi apresentado em meados de 1999 e, a partir do PHP 4.0, lançado em maio de 2000, foi o núcleo do PHP. Desde então foi várias vezes profundamente revisto.

| Versão do PHP | Motor | Principal alteração segundo o manual e os RFC |
|---|---|---|
| PHP 4.0 (2000) | Zend Engine | primeiro núcleo comum, melhor desempenho |
| PHP 5.0 (2004) | Zend Engine 2.0 | novo modelo de objetos |
| PHP 7.0 (2015) | Zend Engine 3.0 | PHPNG: estruturas de dados mais compactas, AST |
| PHP 8.0 (2020) | evolução | compilador JIT como parte do OPcache |

## Os componentes: compilador, máquina virtual, memória

O motor trabalha em fases claramente separadas. Desde o PHP 7, segundo o RFC sobre a árvore sintática abstrata, há três fases até ao bytecode:

1. **Lexer:** decompõe o código-fonte em tokens, por exemplo palavras-chave, nomes de variáveis e cadeias de carateres.
2. **Parser:** constrói a partir dos tokens uma árvore sintática abstrata (AST) que representa a estrutura do programa.
3. **Compilador:** gera a partir da AST op-arrays, isto é, listas de opcodes, uma por ficheiro e função.
4. **Executor (Zend VM):** processa os opcodes. Segundo o RFC do JIT, a cada opcode corresponde uma função handler que o executa.
5. **Gestão de memória:** reserva e liberta memória para cada pedido e vigia nisso o limite de `memory_limit`.

Os tokens de um script podem tornar-se visíveis com a extensão Tokenizer. É inofensivo e instrutivo:

```php
<?php
$code = '<?php $summe = 2 + 3; echo $summe;';
foreach (token_get_all($code) as $token) {
    if (is_array($token)) {
        echo token_name($token[0]), ': ', trim($token[1]), "\n";
    } else {
        echo 'Zeichen: ', $token, "\n";
    }
}
```

A saída mostra entradas como `T_VARIABLE: $summe` ou `T_LNUMBER: 2`. É com estes elementos que o parser continua a trabalhar.

## Como gere a Zend Engine as variáveis?

Segundo o manual, cada variável PHP está num contentor chamado zval. Contém o tipo e o valor, bem como dados de gestão, entre eles um contador de referências (refcount). O contador indica quantos nomes de variáveis apontam para o mesmo contentor.

```php
<?php
$a = str_repeat('x', 10);
$b = $a;        // sem cópia, ambas apontam para o mesmo valor
$b .= 'y';      // só agora se copia (copy on write)
unset($a);      // o contador desce, a memória é libertada ao chegar a 0
```

Quando o contador chega a zero, o motor liberta a memória. Para referências circulares entre objetos existe ainda um garbage collector. Mais sobre isto no artigo [Gestão de memória no PHP](https://phpsos.de/pt/php/speicherverwaltung/).

A revisão PHPNG para o PHP 7 atuou precisamente aqui. Segundo o RFC de Dmitry Stogov e Zeev Suraski, tratava-se de estruturas de dados mais compactas e de uma representação mais hábil dos valores. O RFC indicava ganhos de desempenho de 20 a 110 por cento em aplicações reais.

## OPcache e JIT: extensões do motor

Sem cache, o motor traduz cada script de novo a cada pedido. O [OPcache](https://phpsos.de/pt/php/opcache/) mantém os opcodes prontos na memória partilhada. Desde o PHP 8.0 existe ainda um compilador JIT. Segundo o RFC, assenta no DynASM, uma ferramenta do projeto LuaJIT, e gera código máquina diretamente a partir do bytecode. A máquina virtual permanece inalterada; o JIT substitui apenas os pontos de entrada dos handlers.

Para os operadores isto significa: o OPcache e o JIT aceleram o motor, mas não alteram o seu comportamento perante erros. Uma falha no núcleo mantém-se mesmo com a cache ativa.

## Porque é que as falhas no motor pesam especialmente

As duas vulnerabilidades do PHP2Shell estão no núcleo do PHP. No CVE-2026-109618, uma condição de falta de memória pode interromper o motor enquanto os dados do pedido estão só parcialmente inicializados; na limpeza, dados inválidos são então tratados como válidos. No CVE-2026-109619, o estado interno persiste depois de a memória ser libertada e pode ser usado por um pedido posterior no mesmo worker.

As versões corrigidas 8.5.12, 8.4.27, 8.3.36 e 8.2.35 alteram também, segundo o manual do PHP, o comportamento do limite de memória: `memory_limit` é aí um limite flexível, e uma nova definição `memory_hard_limit_percent` fixa um limite máximo rígido. O manual indica que uma versão que não conheça esta definição está afetada pelas vulnerabilidades. Em distribuições com backports conta ainda o changelog do pacote.

> **Importante:**
> O motor está carregado em cada processo PHP. Depois da atualização, têm por isso de ser reiniciados todos os workers do PHP-FPM, os processos Apache com mod_php e os restantes serviços PHP.

O que acontece no interior perante uma falta de memória descreve-o o artigo [memory_limit e falta de memória](https://phpsos.de/pt/php/out-of-memory/). O enquadramento da própria vulnerabilidade está em [CVE-2026-109618](https://phpsos.de/pt/php2shell/cve-2026-109618/).

## Como ajuda concretamente a PHP SOS?

- **Verificar a versão e o estado dos pacotes:** Apuramos que versão do motor está realmente em execução, incluindo os backports da sua distribuição.
- **Atualizar e reiniciar:** Através do [serviço de patches PHP](https://phpsos.de/pt/leistungen/php-patch-service/) aplicamos a atualização e controlamos que não sobra nenhum processo com código antigo.
- **Definir limites de memória com critério:** Ajustamos `memory_limit`, o novo limite rígido e os limites de cgroup à sua aplicação.
- **Investigar anomalias:** Avaliamos falhas de workers ou processos com estado de saída 137 e verificamos se pode haver um ataque por trás.


## Perguntas frequentes

**De onde vem o nome Zend Engine?**  
O nome compõe-se dos nomes próprios dos seus criadores: Zeev Suraski e Andi Gutmans. Segundo o manual do PHP, o motor foi apresentado em meados de 1999 e, a partir do PHP 4.0, em maio de 2000, foi o núcleo do PHP.

**A Zend Engine é um produto à parte que tenho de instalar?**  
Não. A Zend Engine é parte integrante de qualquer instalação do PHP. Quem atualiza o PHP atualiza automaticamente também o motor. Não tem nada que ver com os produtos comerciais da empresa Zend.

**O que é um opcode?**  
Um opcode é uma instrução isolada para a máquina virtual do PHP, por exemplo uma adição, uma chamada de função ou uma atribuição. O compilador traduz cada script numa sequência dessas instruções, que o motor depois processa.

**O que tem a Zend Engine que ver com o memory_limit?**  
O motor gere a memória de cada pedido e respeita nisso o limite definido em memory_limit. Desde as versões de segurança de 21/10/2026, esse limite é, segundo o manual, um limite flexível, complementado por um limite rígido através de memory_hard_limit_percent.

## Fontes

- [Manual do PHP: história do PHP](https://www.php.net/manual/en/history.php.php)
- [PHP RFC: PHPNG](https://wiki.php.net/rfc/phpng)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
- [Manual do PHP: contagem de referências](https://www.php.net/manual/en/features.gc.refcounting-basics.php)
- [Manual do PHP: definições do núcleo (memory_limit)](https://www.php.net/manual/en/ini.core.php)
