Depurar con Xdebug o PHP Debugger, a mano o con una IA
El IDE de JumPHP tiene un verdadero depurador paso a paso: se detiene el programa en una línea, se miran las variables, se cambia una y se avanza paso a paso. Habla DBGp, el protocolo de Xdebug, y por eso puede manejar dos motores:
- Xdebug, el clásico (por defecto);
- PHP Debugger, un depurador DBGp más reciente, libre y de código abierto, compatible con los ajustes de Xdebug, con una sobrecarga casi nula.
Ambos se manejan igual en el IDE. También puedes confiar el depurador a una IA (Claude Code): pone los puntos de interrupción, ejecuta el programa, lee las variables y encuentra el error ella sola.
Qué motor elegir
| Xdebug | PHP Debugger | |
|---|---|---|
| En JumPHP | por defecto, todos los runtimes | runtime de escritorio (PHP 8.2 a 8.5) |
| Sobrecarga | PHP va claramente más lento | «near-zero overhead when idle», siempre activo, sin disparador que configurar |
Runtime async (PHP 8.6, runtime: async) |
sí | no: se usa Xdebug en su lugar (bin/jumphp lo dice) |
| IA | el servidor MCP de JumPHP (bin/jumphp debug) |
su propio servidor MCP (dbgp mcp), que también ve la salida del script y los avisos de PHP |
En la práctica: PHP Debugger para el día a día, las ejecuciones largas (un juego que juega 600 fotogramas, una suite de tests) y la depuración con IA. Xdebug si trabajas con el runtime async (hilos) o necesitas algo que solo Xdebug hace. Son intercambiables en el IDE: pruébalos en el mismo proyecto.
La página de PHP Debugger no da ninguna cifra de benchmark: solo afirma un coste casi nulo mientras no depuras. Mide en tu proyecto si la diferencia te importa.
Elegir el motor en el IDE
- El botón Debug de la cabecera (el bicho junto a Run,
Mayús+F9) despliega un menú: Depurar con (Xdebug o PHP Debugger, para esta ejecución) y Motor predeterminado (el que usará un simple clic a partir de entonces). Un clic derecho en el botón abre el mismo menú. - La primera ejecución con un motor construye una imagen Docker una sola vez (aprox. un minuto). Las siguientes arrancan al instante.
- Una notificación avisa cuando el programa nunca se conecta al depurador (terminó antes, o nada tras 3 minutos). La salida de la ventana Run suele decir por qué.
Elegir el motor desde un terminal
Todo pasa por bin/jumphp, como siempre:
# Xdebug (por defecto)
JUMPHP_XDEBUG=9003 bin/jumphp test pong
# PHP Debugger
JUMPHP_DEBUGGER=php-debugger JUMPHP_XDEBUG=9003 bin/jumphp test pong
JUMPHP_XDEBUG=<puerto>activa el paso a paso: PHP se conecta a un depurador que escucha en ese puerto de tu ordenador (composer, phpstan yphp -lcorren sin él).JUMPHP_DEBUGGER=xdebug|php-debuggerelige el motor (xdebugpor defecto).- Con
php-debugger,bin/jumphpconstruye una vez la imagendocker/desktop-phpdebugger, a partir de la imagen de escritorio, que se queda sin él. - En el runtime async (PHP 8.6) aparece el mensaje «PHP Debugger does not run on PHP 8.6 (async runtime): Xdebug is used» y corre Xdebug.
Depurar a mano en el IDE
- Punto de interrupción: haz clic en el margen, a la izquierda de una línea de PHP. Un clic derecho da una condición (una expresión PHP: solo se detiene si es verdadera, p. ej.
$this->score < 0);Ctrl+F8pone uno bajo el cursor. Los puntos se guardan por proyecto y siguen a sus líneas al editar. - Debug (
Mayús+F9): el programa corre y se detiene en el primer punto. La línea queda marcada y se abre la ventana Debug. - Mirar: la pila de llamadas (haz clic en un marco para ver sus variables), las variables en árbol leídas bajo demanda, las vigilancias (watches) y un campo para evaluar cualquier expresión PHP donde el programa se detuvo.
- Cambiar un valor: doble clic en una variable o
F2, escribe una expresión PHP (9,"Ada",[1, 2],null) y sigue con el nuevo valor. - Avanzar: Reanudar
F9, Paso por encimaF8, Paso al interiorF7, Paso hacia fueraMayús+F8, Ejecutar hasta el cursorAlt+F9, Detener. - Excepciones: Detener en excepciones… (el icono de aviso de la ventana Debug):
*o nombres de clase (TypeError,App\GameOver). Se detiene donde se lanza la excepción, capturada o no, e indica cuál con su mensaje.
Inspector al pasar el ratón (en la próxima actualización del IDE): con el programa detenido en un punto de interrupción, pasa el ratón sobre una variable en el editor para obtener un árbol desplegable de su valor, con Copiar y Editar.
Un consejo para los juegos: depura ejecuciones sin ventana (test, shot): un juego detenido dentro de una ventana se congela hasta que continúes.
Depurar con una IA
Una IA depura mejor con un depurador que con var_dump(): lee los valores reales, una pregunta cada vez, sin tocar tu código. Hay dos servidores MCP. Usa uno a la vez (los dos escuchan en el puerto 9003).
1. El servidor de JumPHP: bin/jumphp debug
El depurador del propio IDE como servidor MCP (corre en Docker, con Xdebug):
claude mcp add jumphp-debug -- bin/jumphp debug
Sus herramientas:
| Herramienta | Qué hace |
|---|---|
debug_breakpoints |
pone los puntos de un archivo (lines, o {line, condition}), los lista sin ruta, clear_all |
debug_exceptions |
las excepciones que detienen el programa (* = todas, [] = ninguna) |
debug_wait |
espera a que el programa se detenga en un punto o una excepción, y da dónde, la pila y las variables |
debug_state |
dónde está detenido, la pila, las variables de un marco |
debug_step |
step_over, step_into, step_out, run, stop: espera la siguiente parada |
debug_run_to |
avanza hasta una línea |
debug_eval |
evalúa una expresión PHP donde se detuvo |
debug_variables |
las variables de un marco, o los hijos de una ($this->player, $list[3]) |
debug_set_value |
da un nuevo valor a una variable (una expresión PHP) |
Las rutas son relativas al proyecto. Claude lanza el programa él mismo, en segundo plano, con JUMPHP_XDEBUG=9003, y luego llama a debug_wait.
2. El servidor de PHP Debugger: dbgp mcp
PHP Debugger trae su propio servidor MCP en un programa pequeño, dbgp (licencia MIT; Linux y macOS, amd64 y arm64; Windows amd64).
# instalación (macOS / Linux)
curl -fsSL https://github.com/php-debugger/dbgp-client/releases/latest/download/install.sh | sh
dbgp -version
# para este proyecto / para todos tus proyectos
claude mcp add dbgp -- dbgp mcp
claude mcp add --scope user dbgp -- dbgp mcp
En Claude Code, /mcp muestra que está conectado. Sus herramientas, con los nombres de la documentación de PHP Debugger:
- conexión:
status,listen,unlisten,sessions,wait_for_session,detach; - puntos de interrupción:
add_breakpoint,remove_breakpoint,breakpoints; - ejecución:
continue,wait_for_stop,stop; - mirar:
stack,variables,variable,variable_value,source,output,warnings; - actuar:
eval,set_variable; - Docker / remoto:
add_path_mapping,path_mappings.
Opciones útiles (dbgp mcp -h para todas): -php-port PUERTO (el puerto al que se conecta PHP, 9003 por defecto), -mcp-port PUERTO, -idekey CLAVE, -map LOCAL=REMOTO (una correspondencia de rutas, repetible) y -no-eval, que prohíbe eval, set_variable y los puntos condicionales: la IA solo puede mirar. No oculta los valores: contraseñas y claves siguen siendo visibles para ella.
Con bin/jumphp, JUMPHP_DEBUGGER=php-debugger bin/jumphp debug lanza dbgp mcp por ti (necesita dbgp instalado en tu ordenador). Luego lanza el programa con el mismo motor:
JUMPHP_DEBUGGER=php-debugger JUMPHP_XDEBUG=9003 bin/jumphp test pong
Una sesión de ejemplo
Tú, a Claude Code:
La puntuación del juego
pongsube 2 en vez de 1 cuando la bola pasa la pala izquierda. Usa el depurador, no var_dump. Pon un punto de interrupción donde sube la puntuación (busca enPlayScene), ejecutabin/jumphp test pongconJUMPHP_XDEBUG=9003, párate ahí, lee las variables y dime por qué. Corrige solo después de enseñarme la causa.
Lo que hace entonces la IA, con las herramientas de arriba:
- encuentra la línea que suma un punto y pone ahí un punto de interrupción, con una condición si la línea se ejecuta en cada fotograma (
$this->ballX < 0); - lanza el test en segundo plano y espera la parada (
debug_wait/wait_for_stop); - lee
$this->score,$this->scoredy la pila para ver quién llamó a esa línea; - sale una vez (
debug_stepstep_out) para ver al segundo llamante: el punto se cuenta dos veces; - comprueba su idea sin editar nada: da un valor a
$this->scored(debug_set_value/set_variable) y continúa para ver que la puntuación queda bien; - solo entonces edita el código y repite el test, sin punto de interrupción.
Consejos
- Dilo claro: «usa el depurador». Si no, un agente suele volver a
var_dump(). - Dale el comando que muestra el error, lo que esperas y dónde sospechas.
- Pasos pequeños: unos
step_overy mirar. Un punto condicional ($enemy->hp <= 0) vale más que 600 fotogramas paso a paso. - Déjala leer variables y evaluar expresiones: sin
var_dump(), sinecho, nada que limpiar después. - Prefiere las ejecuciones sin ventana (
test,shot,php). - Secretos: la IA ve todas las variables que lee (contraseñas, tokens, claves de API). Depura con datos de prueba y usa
-no-evalcondbgpsi no quieres que ejecute código en tu programa. - No dejes conectado el servidor MCP de un depurador en un proyecto donde no depuras: quítalo con
claude mcp remove.
Solución de problemas
Nada se detiene / «did not connect».
¿Escucha un depurador en el puerto (la ventana Debug del IDE o un servidor MCP)? El programa debe lanzarse con JUMPHP_XDEBUG=<puerto> y el mismo motor que el que escucha.
Puerto ya en uso.
Dos oyentes en 9003: el IDE y bin/jumphp debug (o dbgp mcp), o dos IDE. Para uno, o usa otro puerto: JUMPHP_DEBUG_PORT=9010 bin/jumphp debug con JUMPHP_XDEBUG=9010, o dbgp -php-port 9010 mcp.
El punto de interrupción nunca se alcanza.
Está en una línea sin código (comentario, línea vacía, llave de cierre) o en un archivo que el programa nunca carga. Usa debug_state / mira la pila para ver dónde está. Con un -map o un IDE: las rutas deben coincidir (abajo).
Rutas en Docker.
bin/jumphp monta tu proyecto en /workspace del contenedor: el depurador dice file:///workspace/.... El IDE y bin/jumphp debug lo asocian solos con los archivos del proyecto, y las rutas que das son relativas al proyecto. Con dbgp mcp solo, asocia las carpetas: dbgp mcp -map /home/tu/proyecto=/workspace.
PHP 8.6 (runtime async).
PHP Debugger no corre ahí: se usa Xdebug. Para usar PHP Debugger, depura en el runtime por defecto (PHP 8.5) o quita runtime: async durante la sesión.
Juegos en el navegador.
El depurador trabaja en el runtime de escritorio. En el navegador, reproduce el error con bin/jumphp test o shot en el escritorio.
Ver también Programar, ejecutar y probar, Claude en el IDE e IDE Remote.