0Pricing
PHP Academy · Aula

Como funciona o Zend Engine

Acompanhe o PHP do código-fonte aos opcodes e à execução.

Como funciona o Zend Engine é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

Por Dentro do Mecanismo

O PHP não é interpretado linha por linha a partir do código-fonte. O mecanismo Zend compila o seu script em uma representação intermediária chamada códigos de operação, que são então executados por uma máquina virtual. Compreender esse fluxo explica o desempenho, o OPcache e o JIT.

Esta lição percorre o caminho código-fonte → tokens → AST → códigos de operação → execução da VM.

O Fluxo

Cada requisição a um arquivo PHP passa por quatro fases:

  • Análise léxica — texto do código-fonte → tokens (analisador baseado em re2c)
  • Análise sintática — tokens → Árvore Sintática Abstrata (gramática Bison)
  • Compilação — AST → matriz de códigos de operação (op_array)
  • Execução — a VM Zend percorre os códigos de operação

Sem o OPcache, as três primeiras fases se repetem em cada requisição.

Tokenização

O analisador léxico transforma caracteres em tokens como T_VARIABLE, T_ECHO, T_STRING. O PHP expõe essa etapa por meio de token_get_all() / PhpToken, exatamente o que ferramentas como PHP-CS-Fixer utilizam.

<?php
$src = '<?php $x = 1 + 2; echo $x;';

foreach (PhpToken::tokenize($src) as $tok) {
    if ($tok->isIgnorable()) continue;   // skip whitespace
    printf("%-12s %s\n", $tok->getTokenName(), trim($tok->text));
}
?>

A AST

Os tokens são analisados em uma árvore de nós — um nó de atribuição cujos filhos são uma variável e uma expressão de operação binária. O PHP cria essa AST internamente (e o nikic/php-parser reconstrói uma equivalente no código do usuário para ferramentas de análise estática como o PHPStan).

<?php
// Conceptual AST for:  $x = 1 + 2;
//
//   AST_ASSIGN
//   ├── AST_VAR  ($x)
//   └── AST_BINARY_OP (+)
//       ├── 1
//       └── 2
//
// At compile time PHP folds 1 + 2 into a literal 3
// (constant folding) before generating opcodes.
echo "AST drives opcode generation\n";
?>

Códigos de Operação

O compilador emite um op_array: uma lista linear de códigos de operação. Cada código de operação tem um número de código de operação (por exemplo, ZEND_ADD, ZEND_ECHO, ZEND_ASSIGN) e até dois operandos e um resultado, cada um sendo uma variável compilada (CV), um temporário (TMP) ou uma constante.

<?php
// Opcodes for:  $x = 1 + 2; echo $x;
//
// line  op            operands           result
//  ---  ------------  -----------------  -------
//   1   ADD           1, 2               ~0
//   1   ASSIGN        $x, ~0
//   1   ECHO          $x
//   1   RETURN        1
//
// ~0 is a temporary; $x is a compiled variable (CV).
echo "op_array is what OPcache stores\n";
?>

Inspecionando Códigos de Operação

É possível despejar os códigos de operação gerados com a extensão VLD ou com opcache.opt_debug_level do OPcache. Isso revela a propagação de constantes, a eliminação de código morto e como o fluxo de controle se transforma em códigos de operação JMP/JMPZ.

# Dump opcodes with VLD
php -d vld.active=1 -d vld.execute=0 script.php

# Or via OPcache optimizer debug (pre/post optimization)
php -d opcache.opt_debug_level=0x10000 script.php   # before opt
php -d opcache.opt_debug_level=0x20000 script.php   # after opt

Variáveis Compiladas (CVs)

Variáveis locais não são consultas a tabelas de dispersão no código compilado — o compilador atribui a cada uma uma posição de CV numerada. Acessar $x pela segunda vez corresponde a acessar um índice de matriz, não a pesquisar na tabela de símbolos. Esse é um dos principais motivos pelos quais as variáveis locais são rápidas.

<?php
// Each named local gets a fixed CV slot at compile time:
//   $a -> CV0   $b -> CV1   $sum -> CV2
function add(int $a, int $b): int {
    $sum = $a + $b;   // ADD CV0, CV1 -> CV2
    return $sum;      // RETURN CV2
}
echo add(2, 3) . PHP_EOL;
?>

O Laço de Execução da VM

O executor (execute_ex) percorre o op_array. Cada código de operação corresponde a uma função de tratamento; o PHP pode implementar esse despacho como um switch gigantesco, saltos calculados ou um híbrido (o padrão, e a opção mais rápida nos compiladores compatíveis). O ponteiro opline avança; os códigos de operação JMP o movem para controlar o fluxo.

<?php
// if ($n > 0) echo 'pos'; compiles roughly to:
//
//   IS_SMALLER 0, $n  -> ~T
//   JMPZ ~T, ->L1        ; if false, skip
//   ECHO 'pos'
// L1:
//   RETURN 1
//
// The VM follows opline; JMPZ rewrites it conditionally.
$n = 5;
if ($n > 0) echo "pos\n";
?>

Onde o OPcache se Encaixa

O OPcache armazena o op_array na memória compartilhada, ignorando a análise léxica, a análise sintática e a compilação nas requisições seguintes. Ele também executa uma etapa de otimização (propagação de constantes, remoção de código morto e fusão de códigos de operação). A VM ainda executa os códigos de operação armazenados em cache a cada requisição — é aí que o JIT ajuda posteriormente.

Sobrecarga das Chamadas de Função

As chamadas empilham um novo quadro de pilha da VM: os códigos de operação INIT_FCALL, SEND_VAL/SEND_VAR para cada argumento e, em seguida, DO_FCALL. Saber disso explica por que chamadas excessivas a funções minúsculas têm um custo mensurável e por que a expansão de funções e o JIT são importantes em laços intensivos.

<?php
// square($x) compiles to a call sequence:
//   INIT_FCALL 'square'
//   SEND_VAR   $x
//   DO_FCALL        -> ~R
//   ASSIGN $y, ~R
function square(int $x): int { return $x * $x; }

$total = 0;
for ($i = 1; $i <= 5; $i++) {
    $total += square($i);   // one call sequence per iteration
}
echo $total . PHP_EOL;     // 1+4+9+16+25 = 55
?>

Encerramento da Requisição

Após a execução, o PHP desmonta a requisição: as variáveis em execução são liberadas, a saída é descarregada e, em seguida, o mecanismo reinicializa sua arena do alocador. No modelo FPM sem compartilhamento, cada requisição começa limpa — por isso um erro fatal em uma requisição não pode corromper outra. Os op_arrays compartilhados do OPcache sobrevivem entre requisições; o estado do executor, não.

Verificação Rápida

O que exatamente o OPcache armazena para evitar a recompilação?

Resumo

O fluxo Zend é análise léxica → análise sintática → compilação → execução. O código-fonte se transforma em tokens, depois em uma AST e, por fim, em um op_array de códigos de operação executados pelo laço do executor da VM, com as variáveis locais armazenadas em posições de CV numeradas e as chamadas empilhando quadros. O OPcache armazena o op_array (além de executar uma etapa de otimização), de modo que apenas a execução se repete a cada requisição.

Perguntas Frequentes

A aula “Como funciona o Zend Engine” é grátis?

Sim — o texto completo de “Como funciona o Zend Engine” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Como funciona o Zend Engine”?

Acompanhe o PHP do código-fonte aos opcodes e à execução. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Como funciona o Zend Engine”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Como funciona o Zend Engine
  2. Gerenciamento de memória e coleta de lixo
  3. OPcache e compilação JIT
  4. Escrevendo uma extensão PHP básica em C
← Voltar para PHP Academy