JA

XdebugまたはPHP Debuggerでデバッグする: 手動でもAIとでも

JumPHP IDEには本格的なステップデバッガーがあります。プログラムを任意の行で止め、変数を確認し、1つを書き換えて、1ステップずつ進められます。XdebugのプロトコルであるDBGpを話すので、2つのエンジンを操作できます。

  • 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回ビルドされます(1分ほど)。2回目以降はすぐに始まります。
  • プログラムがデバッガーに接続しなかった場合(先に終了した、または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を1回ビルドします。デスクトップイメージ自体には手が加わりません。
  • 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()よりもデバッガーを使うほうがうまくデバッグできます。実際の値を、1回に1つの問いで読み、コードには何も手を加えません。MCPサーバーは2つあります。同時に使うのはどちらか1つです(どちらもポート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)2つ目の呼び出し元を確認する。点が二重に数えられている。
  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で2つが待ち受けています。IDEとbin/jumphp debug(またはdbgp mcp)、あるいは2つの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 もご覧ください。