로그인
KO

Xdebug 또는 PHP Debugger로 디버깅하기: 직접 또는 AI와 함께

JumPHP IDE에는 진짜 단계별 디버거가 있습니다. 프로그램을 한 줄에서 멈추고, 변수를 살펴보고, 하나를 바꾼 다음, 한 단계씩 계속 진행할 수 있습니다. Xdebug의 프로토콜인 DBGp를 사용하므로 두 가지 엔진을 구동할 수 있습니다.

  • Xdebug: 고전적인 엔진 (기본값).
  • PHP Debugger: 더 새로운 DBGp 디버거로, 무료 오픈 소스이며 Xdebug의 설정과 호환되고 오버헤드가 거의 없습니다.

IDE에서는 둘이 똑같이 동작합니다. 디버거를 AI(Claude Code)에게 맡길 수도 있습니다. AI가 직접 중단점을 설정하고, 프로그램을 실행하고, 변수를 읽고, 버그를 찾아냅니다.

어떤 엔진을 고를까

Xdebug PHP Debugger
JumPHP에서 기본값, 모든 런타임 데스크톱 런타임 (PHP 8.2~8.5)
오버헤드 PHP가 눈에 띄게 느려짐 "near-zero overhead when idle", 항상 켜져 있고 설정할 트리거 없음
async 런타임 (PHP 8.6, runtime: async) 지원 미지원: 대신 Xdebug가 사용되며 IDE가 알려 줍니다
AI JumPHP MCP 서버 (bin/jumphp debug) 자체 MCP 서버 (dbgp mcp), 스크립트의 출력과 PHP 경고도 볼 수 있음

실제로는 일상적인 디버깅, 오래 걸리는 실행(600프레임을 플레이하는 게임, 테스트 모음), AI 디버깅에는 PHP Debugger를 고르세요. async 런타임(스레드)으로 작업하거나 Xdebug만 할 수 있는 기능이 필요하다면 Xdebug를 그대로 쓰세요. IDE에서 둘은 서로 바꿔 쓸 수 있으므로 같은 프로젝트에서 둘 다 시험해 볼 수 있습니다.

PHP Debugger의 자체 페이지에는 벤치마크 수치가 없습니다. 디버깅하기 전까지 비용이 거의 없다고만 밝히고 있습니다. 차이가 중요하다면 직접 프로젝트에서 측정해 보세요.

IDE에서 엔진 선택하기

  • 헤더의 디버그 버튼(실행 옆의 벌레 아이콘, Shift+F9)은 메뉴를 펼칩니다: 다음으로 디버그(이번 실행에 Xdebug 또는 PHP Debugger 중 무엇을 쓸지)와 기본 엔진(이후 일반 클릭이 사용할 엔진). 버튼을 마우스 오른쪽 버튼으로 클릭해도 같은 메뉴가 열립니다.
  • 특정 엔진으로 처음 실행하면 Docker 이미지를 한 번 빌드합니다(약 1분). 이후 실행은 바로 시작됩니다.
  • 프로그램이 디버거에 끝내 연결되지 않으면(먼저 종료되었거나 3분이 지나도 아무 일도 없을 때) 알림이 표시됩니다. 이유는 대개 실행 창의 출력에 나옵니다.

터미널에서 엔진 선택하기

언제나처럼 모든 것은 bin/jumphp를 통합니다.

# Xdebug (default)
JUMPHP_XDEBUG=9003 bin/jumphp test pong

# PHP Debugger
JUMPHP_DEBUGGER=php-debugger JUMPHP_XDEBUG=9003 bin/jumphp test pong
  • JUMPHP_XDEBUG=<port>는 단계별 디버깅을 켭니다. PHP가 컴퓨터의 해당 포트에서 대기 중인 디버거에 연결합니다(composer, phpstan, php -l은 이것 없이 실행됩니다).
  • JUMPHP_DEBUGGER=xdebug|php-debugger는 엔진을 선택합니다(기본값 xdebug).
  • php-debugger를 쓰면 bin/jumphp가 데스크톱 이미지를 바탕으로 이미지 docker/desktop-phpdebugger를 한 번 빌드합니다. 데스크톱 이미지 자체는 그대로 유지됩니다.
  • async 런타임(PHP 8.6)에서는 "PHP Debugger does not run on PHP 8.6 (async runtime): Xdebug is used" 메시지가 표시되고 Xdebug가 실행됩니다.

IDE에서 직접 디버깅하기

  1. 중단점: PHP 줄 왼쪽의 여백을 클릭합니다. 오른쪽 클릭으로 조건(PHP 식: 참일 때만 멈춤, 예: $this->score < 0)을 줄 수 있고, Ctrl+F8은 커서 위치에 중단점을 설정합니다. 중단점은 프로젝트별로 저장되며, 편집하는 동안 해당 줄을 따라갑니다.
  2. 디버그 (Shift+F9): 프로그램이 실행되어 첫 번째 중단점에서 멈춥니다. 해당 줄이 표시되고 Debug 도구 창이 열립니다.
  3. 살펴보기: 호출 스택(프레임을 클릭하면 그 변수를 볼 수 있음), 필요할 때 읽어 오는 트리 형태의 변수, watches, 멈춘 지점에서 임의의 PHP 식을 평가하는 입력란.
  4. 값 바꾸기: 변수를 더블 클릭하거나 F2를 누르고 PHP 식(9, "Ada", [1, 2], null)을 입력한 뒤 새 값으로 계속 진행합니다.
  5. 이동: 재개 F9, 단계 건너뛰기 F8, 단계 진입 F7, 단계 나가기 Shift+F8, 커서까지 실행 Alt+F9, 중지.
  6. 예외: 예외에서 중단… (Debug 창의 경고 아이콘): * 또는 클래스 이름(TypeError, App\GameOver). 예외가 잡히든 아니든 던져진 곳에서 멈추며, 어떤 예외인지 메시지와 함께 보여 줍니다.

마우스 오버 인스펙터 (다음 IDE 업데이트 예정): 프로그램이 중단점에서 멈춰 있을 때 편집기에서 변수 위로 마우스를 가져가면 값의 펼칠 수 있는 트리가 나타나며 Copy와 Edit를 쓸 수 있습니다.

게임을 위한 팁: 헤드리스 실행(test, shot)을 디버깅하세요. 창 안에서 멈춘 게임은 재개할 때까지 멈춰 있습니다.

AI와 함께 디버깅하기

AI는 var_dump()보다 디버거로 더 잘 디버깅합니다. 실제 값을 한 번에 하나의 질문으로 읽고, 코드는 전혀 바꾸지 않습니다. MCP 서버는 두 가지가 있습니다. 한 번에 하나만 사용하세요(둘 다 9003 포트에서 대기합니다).

1. JumPHP 서버: bin/jumphp debug

IDE 자체의 디버거를 MCP 서버로 제공합니다(Docker에서 Xdebug로 실행).

claude mcp add jumphp-debug -- bin/jumphp debug

도구:

도구 기능
debug_breakpoints 파일의 중단점 설정(lines 또는 {line, condition}), 경로 없이 호출하면 목록 표시, clear_all
debug_exceptions 프로그램을 멈추게 하는 예외(* = 전체, [] = 없음)
debug_wait 프로그램이 중단점이나 예외에서 멈출 때까지 기다린 뒤 위치, 스택, 변수를 알려 줌
debug_state 멈춘 위치, 스택, 프레임의 변수
debug_step step_over, step_into, step_out, run, stop: 다음 정지를 기다림
debug_run_to 지정한 줄까지 실행
debug_eval 멈춘 지점에서 PHP 식을 평가
debug_variables 프레임의 변수 또는 그중 하나의 자식($this->player, $list[3])
debug_set_value 변수에 새 값(PHP 식)을 지정

경로는 프로젝트 기준 상대 경로입니다. Claude는 프로그램을 직접 백그라운드에서 JUMPHP_XDEBUG=9003으로 시작한 다음 debug_wait를 호출합니다.

2. PHP Debugger의 서버: dbgp mcp

PHP Debugger는 작은 프로그램 dbgp에 자체 MCP 서버를 담아 제공합니다(MIT 라이선스, Linux와 macOS는 amd64와 arm64, Windows는 amd64).

# install (macOS / Linux)
curl -fsSL https://github.com/php-debugger/dbgp-client/releases/latest/download/install.sh | sh
dbgp -version

# for this project / for all your projects
claude mcp add dbgp -- dbgp mcp
claude mcp add --scope user dbgp -- dbgp mcp

Claude Code 안에서 /mcp로 연결되었는지 확인할 수 있습니다. 도구는 PHP Debugger 문서의 이름으로 다음과 같습니다.

  • 연결: status, listen, unlisten, sessions, wait_for_session, detach;
  • 중단점: add_breakpoint, remove_breakpoint, breakpoints;
  • 실행: continue, wait_for_stop, stop;
  • 살펴보기: stack, variables, variable, variable_value, source, output, warnings;
  • 조작: eval, set_variable;
  • Docker / 원격: add_path_mapping, path_mappings.

유용한 플래그(전체는 dbgp mcp -h): -php-port PORT(PHP가 연결하는 포트, 기본값 9003), -mcp-port PORT, -idekey KEY, -map LOCAL=REMOTE(경로 매핑, 반복 가능), 그리고 eval, set_variable, 조건부 중단점을 금지하는 -no-eval: AI는 보기만 할 수 있습니다. 값을 숨기지는 않으므로 비밀번호와 키는 AI에게 계속 보입니다.

bin/jumphp를 통하면 JUMPHP_DEBUGGER=php-debugger bin/jumphp debug가 dbgp mcp를 대신 시작합니다(컴퓨터에 dbgp가 설치되어 있어야 합니다). 그런 다음 같은 엔진으로 프로그램을 시작하세요.

JUMPHP_DEBUGGER=php-debugger JUMPHP_XDEBUG=9003 bin/jumphp test pong

실제 세션 예

당신이 Claude Code에게:

pong 게임에서 공이 왼쪽 패들을 지나가면 점수가 1이 아니라 2 올라갑니다. var_dump가 아니라 디버거를 사용하세요. 점수가 올라가는 곳(PlayScene을 보세요)에 중단점을 설정하고, JUMPHP_XDEBUG=9003으로 bin/jumphp test pong을 실행해 그곳에서 멈춘 뒤, 변수를 읽고 이유를 알려 주세요. 원인을 보여 준 다음에만 고치세요.

그러면 AI는 위의 도구로 다음과 같이 합니다.

  1. 점수를 더하는 줄을 찾아 그곳에 중단점을 설정합니다. 그 줄이 매 프레임 실행된다면 조건($this->ballX < 0)을 붙입니다.
  2. 테스트를 백그라운드에서 시작하고 정지를 기다립니다(debug_wait / wait_for_stop).
  3. $this->score, $this->scored와 스택을 읽어 누가 이 줄을 호출했는지 확인합니다.
  4. 한 번 스텝 아웃(debug_step의 step_out)하여 두 번째 호출자를 확인합니다. 점수가 두 번 계산되고 있습니다.
  5. 아무것도 편집하지 않고 가설을 확인합니다. $this->scored에 값을 지정(debug_set_value / set_variable)하고 계속 진행해 점수가 올바르게 유지되는지 봅니다.
  6. 그런 다음에야 코드를 수정하고, 중단점 없이 테스트를 다시 실행합니다.

팁

  • 분명하게 말하세요: "디버거를 사용해". 그렇지 않으면 에이전트가 종종 var_dump()로 돌아갑니다.
  • 버그를 보여 주는 명령, 기대하는 결과, 의심되는 위치를 알려 주세요.
  • 작은 단계로: step_over를 몇 번 한 다음 살펴봅니다. 600프레임을 한 단계씩 넘기는 것보다 조건부 중단점($enemy->hp <= 0)이 낫습니다.
  • 변수를 읽고 식을 평가하게 하세요. var_dump()도 echo도 없고, 나중에 정리할 것도 없습니다.
  • 창보다 헤드리스 실행(test, shot, php)을 선호하세요.
  • 비밀 정보: AI는 읽는 모든 변수(비밀번호, 토큰, API 키)를 봅니다. 테스트 데이터로 디버깅하고, 프로그램에서 코드를 실행하지 못하게 하려면 dbgp에 -no-eval을 사용하세요.
  • 디버깅하지 않는 프로젝트에 디버거의 MCP 서버를 연결해 두지 마세요. claude mcp remove로 제거합니다.

문제 해결

아무것도 멈추지 않음 / "did not connect". 해당 포트에서 디버거가 대기 중인가요(IDE의 Debug 창 또는 MCP 서버)? 프로그램은 JUMPHP_XDEBUG=<port>와, 대기 중인 쪽과 같은 엔진으로 시작해야 합니다.

포트가 이미 사용 중. 9003에 대기자가 둘입니다. IDE와 bin/jumphp debug(또는 dbgp mcp), 혹은 IDE 두 개입니다. 하나를 멈추거나 다른 포트를 사용하세요: JUMPHP_XDEBUG=9010과 함께 JUMPHP_DEBUG_PORT=9010 bin/jumphp debug, 또는 dbgp -php-port 9010 mcp.

중단점에 도달하지 않음. 코드가 없는 줄(주석, 빈 줄, 닫는 중괄호)에 있거나, 프로그램이 한 번도 로드하지 않는 파일에 있습니다. debug_state를 실행하거나 스택을 보고 어디에 있는지 확인하세요. -map이나 IDE를 쓸 때는 경로가 일치해야 합니다(아래 참조).

Docker의 경로. bin/jumphp는 컨테이너 안의 /workspace에 프로젝트를 마운트하므로 디버거는 file:///workspace/...라고 보고합니다. IDE와 bin/jumphp debug는 이를 프로젝트 파일에 자동으로 매핑하며, 지정하는 경로는 프로젝트 기준 상대 경로입니다. dbgp mcp만 쓸 때는 폴더를 매핑하세요: dbgp mcp -map /home/you/project=/workspace.

PHP 8.6 (async 런타임). PHP Debugger는 여기서 실행되지 않으며 Xdebug가 사용됩니다. PHP Debugger를 쓰려면 기본 런타임(PHP 8.5)에서 디버깅하거나, 해당 세션 동안 runtime: async를 제거하세요.

브라우저 게임. 디버거는 데스크톱 런타임에서 동작합니다. 브라우저에서는 데스크톱에서 bin/jumphp test 또는 shot으로 버그를 재현하세요.

함께 보기: 코딩, 실행, 테스트, IDE의 Claude, IDE Remote.