Depurar com Xdebug ou PHP Debugger, à mão ou com uma IA
O IDE do JumPHP tem um verdadeiro depurador passo a passo: pára-se o programa numa linha, veem-se as variáveis, muda-se uma e avança-se passo a passo. Fala DBGp, o protocolo do Xdebug, e por isso pode comandar dois motores:
- Xdebug, o clássico (por defeito);
- PHP Debugger, um depurador DBGp mais recente, livre e de código aberto, compatível com as definições do Xdebug, com sobrecarga quase nula.
Os dois usam-se da mesma maneira no IDE. Também podes confiar o depurador a uma IA (Claude Code): ela põe os pontos de paragem, executa o programa, lê as variáveis e encontra o erro sozinha.
Que motor escolher
| Xdebug | PHP Debugger | |
|---|---|---|
| No JumPHP | por defeito, todos os runtimes | runtime de secretária (PHP 8.2 a 8.5) |
| Sobrecarga | o PHP fica claramente mais lento | «near-zero overhead when idle», sempre ativo, sem gatilho a configurar |
Runtime async (PHP 8.6, runtime: async) |
sim | não: usa-se o Xdebug (o bin/jumphp di-lo) |
| IA | o servidor MCP do JumPHP (bin/jumphp debug) |
o seu servidor MCP (dbgp mcp), que também vê a saída do script e os avisos do PHP |
Na prática: PHP Debugger para o dia a dia, execuções longas (um jogo que joga 600 imagens, uma suite de testes) e depuração com IA. Xdebug se trabalhas com o runtime async (threads) ou precisas do que só o Xdebug faz. São intermutáveis no IDE: experimenta-os no mesmo projeto.
A página do PHP Debugger não dá nenhum número de benchmark: afirma só um custo quase nulo enquanto não se depura. Mede no teu projeto se a diferença te interessa.
Escolher o motor no IDE
- O botão Debug do cabeçalho (o bicho ao lado de Run,
Shift+F9) abre um menu: Depurar com (Xdebug ou PHP Debugger, para esta execução) e Motor padrão (o que um simples clique usará daí em diante). Um clique direito no botão abre o mesmo menu. - A primeira execução com um motor constrói uma imagem Docker uma só vez (cerca de um minuto). As seguintes arrancam logo.
- Uma notificação avisa quando o programa nunca se liga ao depurador (terminou antes, ou nada após 3 minutos). A saída da janela Run costuma dizer porquê.
Escolher o motor a partir de um terminal
Tudo passa pelo bin/jumphp, como sempre:
# Xdebug (por defeito)
JUMPHP_XDEBUG=9003 bin/jumphp test pong
# PHP Debugger
JUMPHP_DEBUGGER=php-debugger JUMPHP_XDEBUG=9003 bin/jumphp test pong
JUMPHP_XDEBUG=<porta>ativa o passo a passo: o PHP liga-se a um depurador que escuta nessa porta do teu computador (composer, phpstan ephp -lcorrem sem ele).JUMPHP_DEBUGGER=xdebug|php-debuggerescolhe o motor (xdebugpor defeito).- Com
php-debugger, obin/jumphpconstrói uma vez a imagemdocker/desktop-phpdebugger, a partir da imagem de secretária, que fica sem ele. - No runtime async (PHP 8.6) aparece a mensagem «PHP Debugger does not run on PHP 8.6 (async runtime): Xdebug is used» e corre o Xdebug.
Depurar à mão no IDE
- Ponto de paragem: clica na margem, à esquerda de uma linha de PHP. Um clique direito dá uma condição (uma expressão PHP: só pára se for verdadeira, p. ex.
$this->score < 0);Ctrl+F8põe um no cursor. Os pontos são guardados por projeto e seguem as suas linhas quando editas. - Debug (
Shift+F9): o programa corre e pára no primeiro ponto. A linha fica marcada e abre-se a janela Debug. - Ver: a pilha de chamadas (clica numa moldura para ver as suas variáveis), as variáveis em árvore lidas a pedido, as vigilâncias (watches) e um campo para avaliar qualquer expressão PHP onde o programa parou.
- Mudar um valor: duplo clique numa variável ou
F2, escreve uma expressão PHP (9,"Ada",[1, 2],null) e continua com o novo valor. - Avançar: Retomar
F9, Passo por cimaF8, Passo para dentroF7, Passo para foraShift+F8, Executar até o cursorAlt+F9, Parar. - Exceções: Parar nas exceções… (o ícone de aviso da janela Debug):
*ou nomes de classes (TypeError,App\GameOver). Pára onde a exceção é lançada, apanhada ou não, e indica qual com a sua mensagem.
Inspetor ao passar o rato (na próxima atualização do IDE): com o programa parado num ponto de paragem, passa o rato sobre uma variável no editor para obter uma árvore expansível do seu valor, com Copiar e Editar.
Uma dica para os jogos: depura execuções sem janela (test, shot): um jogo parado numa janela congela até continuares.
Depurar com uma IA
Uma IA depura melhor com um depurador do que com var_dump(): lê os valores reais, uma pergunta de cada vez, sem tocar no teu código. Há dois servidores MCP. Usa um de cada vez (os dois escutam na porta 9003).
1. O servidor do JumPHP: bin/jumphp debug
O depurador do próprio IDE como servidor MCP (corre no Docker, com Xdebug):
claude mcp add jumphp-debug -- bin/jumphp debug
As suas ferramentas:
| Ferramenta | O que faz |
|---|---|
debug_breakpoints |
define os pontos de um ficheiro (lines, ou {line, condition}), lista-os sem caminho, clear_all |
debug_exceptions |
as exceções que param o programa (* = todas, [] = nenhuma) |
debug_wait |
espera que o programa pare num ponto ou numa exceção, e dá onde, a pilha e as variáveis |
debug_state |
onde está parado, a pilha, as variáveis de uma moldura |
debug_step |
step_over, step_into, step_out, run, stop: espera a paragem seguinte |
debug_run_to |
avança até uma linha |
debug_eval |
avalia uma expressão PHP onde parou |
debug_variables |
as variáveis de uma moldura, ou os filhos de uma ($this->player, $list[3]) |
debug_set_value |
dá um novo valor a uma variável (uma expressão PHP) |
Os caminhos são relativos ao projeto. O Claude lança o programa ele próprio, em segundo plano, com JUMPHP_XDEBUG=9003, e depois chama debug_wait.
2. O servidor do PHP Debugger: dbgp mcp
O PHP Debugger traz o seu próprio servidor MCP num pequeno programa, dbgp (licença MIT; Linux e macOS, amd64 e arm64; Windows amd64).
# instalação (macOS / Linux)
curl -fsSL https://github.com/php-debugger/dbgp-client/releases/latest/download/install.sh | sh
dbgp -version
# para este projeto / para todos os teus projetos
claude mcp add dbgp -- dbgp mcp
claude mcp add --scope user dbgp -- dbgp mcp
No Claude Code, /mcp mostra que está ligado. As suas ferramentas, com os nomes da documentação do PHP Debugger:
- ligação:
status,listen,unlisten,sessions,wait_for_session,detach; - pontos de paragem:
add_breakpoint,remove_breakpoint,breakpoints; - execução:
continue,wait_for_stop,stop; - ver:
stack,variables,variable,variable_value,source,output,warnings; - agir:
eval,set_variable; - Docker / remoto:
add_path_mapping,path_mappings.
Opções úteis (dbgp mcp -h para todas): -php-port PORTA (a porta a que o PHP se liga, 9003 por defeito), -mcp-port PORTA, -idekey CHAVE, -map LOCAL=REMOTO (uma correspondência de caminhos, repetível) e -no-eval, que proíbe eval, set_variable e os pontos condicionais: a IA só pode olhar. Não esconde os valores: palavras-passe e chaves continuam visíveis para ela.
Pelo bin/jumphp, JUMPHP_DEBUGGER=php-debugger bin/jumphp debug lança o dbgp mcp por ti (precisa do dbgp instalado no teu computador). Depois lança o programa com o mesmo motor:
JUMPHP_DEBUGGER=php-debugger JUMPHP_XDEBUG=9003 bin/jumphp test pong
Uma sessão de exemplo
Tu, ao Claude Code:
A pontuação do jogo
pongsobe 2 em vez de 1 quando a bola passa a raquete da esquerda. Usa o depurador, não o var_dump. Põe um ponto de paragem onde a pontuação aumenta (procura emPlayScene), executabin/jumphp test pongcomJUMPHP_XDEBUG=9003, pára aí, lê as variáveis e diz-me porquê. Corrige só depois de me mostrares a causa.
O que a IA faz então, com as ferramentas acima:
- encontra a linha que soma um ponto e põe lá um ponto de paragem, com uma condição se a linha passa a cada imagem (
$this->ballX < 0); - lança o teste em segundo plano e espera a paragem (
debug_wait/wait_for_stop); - lê
$this->score,$this->scorede a pilha para ver quem chamou essa linha; - sai uma vez (
debug_stepstep_out) para ver o segundo chamador: o ponto é contado duas vezes; - verifica a sua ideia sem editar nada: dá um valor a
$this->scored(debug_set_value/set_variable) e continua para ver a pontuação ficar certa; - só então edita o código e repete o teste, sem ponto de paragem.
Dicas
- Diz claramente: «usa o depurador». Senão, um agente volta muitas vezes ao
var_dump(). - Dá-lhe o comando que mostra o erro, o que esperas e onde suspeitas.
- Passos pequenos: uns
step_over, depois olha-se. Um ponto condicional ($enemy->hp <= 0) vale mais do que 600 imagens passo a passo. - Deixa-a ler variáveis e avaliar expressões: sem
var_dump(), semecho, nada a limpar depois. - Prefere as execuções sem janela (
test,shot,php). - Segredos: a IA vê todas as variáveis que lê (palavras-passe, tokens, chaves de API). Depura com dados de teste e usa
-no-evalcom odbgpse não queres que execute código no teu programa. - Não deixes ligado o servidor MCP de um depurador num projeto onde não depuras: tira-o com
claude mcp remove.
Resolução de problemas
Nada pára / «did not connect».
Há um depurador a escutar na porta (a janela Debug do IDE ou um servidor MCP)? O programa tem de ser lançado com JUMPHP_XDEBUG=<porta> e o mesmo motor de quem escuta.
Porta já em uso.
Dois ouvintes em 9003: o IDE e bin/jumphp debug (ou dbgp mcp), ou dois IDE. Pára um, ou usa outra porta: JUMPHP_DEBUG_PORT=9010 bin/jumphp debug com JUMPHP_XDEBUG=9010, ou dbgp -php-port 9010 mcp.
O ponto de paragem nunca é atingido.
Está numa linha sem código (comentário, linha vazia, chaveta de fecho) ou num ficheiro que o programa nunca carrega. Usa debug_state / vê a pilha para saber onde está. Com -map ou um IDE: os caminhos têm de coincidir (abaixo).
Caminhos no Docker.
O bin/jumphp monta o teu projeto em /workspace no contentor: o depurador diz file:///workspace/.... O IDE e o bin/jumphp debug associam isso sozinhos aos ficheiros do projeto, e os caminhos que dás são relativos ao projeto. Com o dbgp mcp sozinho, associa as pastas: dbgp mcp -map /home/tu/projeto=/workspace.
PHP 8.6 (runtime async).
O PHP Debugger não corre aí: usa-se o Xdebug. Para usar o PHP Debugger, depura no runtime por defeito (PHP 8.5) ou tira runtime: async durante a sessão.
Jogos no navegador.
O depurador trabalha no runtime de secretária. No navegador, reproduz o erro com bin/jumphp test ou shot na secretária.
Veja também Programar, iniciar e testar, Claude no IDE e IDE Remote.