公開日 2026-03-15

VS Code + Xdebugでステップ実行入門(WSL2 + Docker)

WSL2とDockerのPHP環境でXdebugを使ったステップ実行を最短で再現する。

目次

  1. 前提環境
  2. 1. ゴールと非対象
  3. 2. 新規デモ環境を作成する(Remote - WSL / Docker)
  4. 3. PHPコンテナでXdebugを有効化する
  5. 4. VS Code の launch.json を設定する
  6. 5. 最小サンプルでブレークポイント確認
  7. 6. start_with_request=yes から trigger へ移行する(任意)
  8. 7. よくある詰まりと復旧手順
  9. 8. まとめと次の一歩

xdebug.ini / launch.json / pathMappings の最小構成を組み合わせ、localhost:8080 への HTTP アクセスで VS Code のブレークポイントに停止する環境を作ります。

対象は WSL2 + Docker + Remote - WSL で PHP を開発中の方です。既存プロジェクトは不要で、記事内で新規デモ環境を作成します。「CLI では見えているのに止まらない」の原因と対処も含みます。

前提環境

  • Windows 11
  • WSL2(Ubuntu)
  • VS Code(Remote - WSL)
  • Docker Desktop(WSL連携有効)

以降のコマンドは、特記がない限り WSL 側ターミナルで実行します。
code --list-extensions も WSL 側で実行してください。

1. ゴールと非対象

この記事で到達する状態:

  • localhost:8080 への HTTP アクセスで、VS Code のブレークポイントに停止できる
  • xdebug.ini / launch.json / 最小サンプルの組み合わせを再現できる
  • start_with_request=yes から trigger へ段階的に切り替えられる

前提条件:

  • VS Code 拡張 xdebug.php-debug は導入済みとする(未導入の場合は 2 章で導入可能)

この記事で扱わない内容:

  • 本番環境での Xdebug 運用
  • 高度な条件付きブレークポイントや PHPUnit 連携
  • PhpStorm など他 IDE との比較

主線は start_with_request=yes です。
trigger は 6 章で任意の運用改善として扱います。

2. 新規デモ環境を作成する(Remote - WSL / Docker)

まず、WSL 側にデモディレクトリを作成します。

mkdir -p ~/projects/vscode-xdebug-step-debug-demo
cd ~/projects/vscode-xdebug-step-debug-demo
mkdir -p docker/php/conf.d .vscode public
code .

docker/php/Dockerfile を作成します。

FROM php:8.5-cli

RUN pecl install xdebug \
    && docker-php-ext-enable xdebug

WORKDIR /var/www/html

compose.yml を作成します(この章では最小起動構成のみ)。

services:
  app:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    working_dir: /var/www/html
    volumes:
      - ./:/var/www/html
    command: ["php", "-S", "0.0.0.0:8080", "-t", "/var/www/html/public"]
    ports:
      - "8080:8080"

起動して前提を確認します。

docker compose up --build -d
docker compose ps
docker compose exec app php -v
docker compose exec app php -m | grep -i xdebug
code --list-extensions | grep -Fx "xdebug.php-debug"

xdebug.php-debug が見つからない場合は、WSL 側で導入してから続行してください。

code --install-extension xdebug.php-debug --force

確認ポイント:

  • docker compose psappUp になっている
  • php -mxdebug が表示される
  • code --list-extensionsxdebug.php-debug が表示される

ここで詰まる場合は、7章のトラブルシュートを先に確認してください。

3. PHPコンテナでXdebugを有効化する

docker/php/conf.d/xdebug.ini を作成します。

xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.log=/tmp/xdebug.log

次に、compose.yml を次の内容に更新します。

services:
  app:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    working_dir: /var/www/html
    volumes:
      - ./:/var/www/html
      - ./docker/php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/99-xdebug.ini:ro
    extra_hosts:
      - "host.docker.internal:host-gateway"
    command: ["php", "-S", "0.0.0.0:8080", "-t", "/var/www/html/public"]
    ports:
      - "8080:8080"

compose.yml の変更反映では再ビルドは不要です。docker compose up -d で再作成して確認します。

docker compose up -d
docker compose exec app php -m | grep -i xdebug
docker compose exec app php -i | grep -E "xdebug.mode|xdebug.client_host|xdebug.client_port|xdebug.start_with_request|xdebug.log"

ポイント:

  • php -i は CLI 設定確認の近道です。最終的に止まるかどうかは 5 章の HTTP アクセスで確認します。
  • xdebug.ini をボリュームマウントしている場合は再起動(docker compose up -d / docker compose restart app)で反映できます。
  • Dockerfile を変更した場合は再ビルド(docker compose up --build -d)が必要です。

4. VS Code の launch.json を設定する

.vscode/launch.json を作成します。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Listen for Xdebug",
      "type": "php",
      "request": "launch",
      "port": 9003,
      "pathMappings": {
        "/var/www/html": "${workspaceFolder}"
      }
    }
  ]
}

pathMappings は灰色ブレークポイント対策の要点です。
上記ではコンテナ側の実パス(remoteRoot)/var/www/html を、ローカル側(localRoot)${workspaceFolder} に対応づけています。

止まるまでの向きを図にすると、次のようになります。ブラウザの HTTP アクセスがきっかけになり、PHP コンテナ内の Xdebug が host.docker.internal:9003 経由で VS Code の待受へ接続します。

sequenceDiagram
    participant Browser
    participant PHP as PHP container
    participant Xdebug
    participant Host as host.docker.internal
    participant VSCode as VS Code

    Browser->>PHP: GET /index.php
    PHP->>Xdebug: start debug session
    Xdebug->>Host: connect to port 9003
    Host->>VSCode: forward to PHP Debug listener
    VSCode-->>Xdebug: breakpoint and step commands
    Xdebug-->>PHP: pause and resume execution
    PHP-->>Browser: HTTP response

xdebug.inilaunch.jsonpathMappings のどこか 1 つでも向きがずれると、「CLI では設定が見えているのに HTTP で止まらない」状態になります。

VS Code 側の操作:

  1. Run and Debug を開く
  2. 構成で Listen for Xdebug を選ぶ
  3. 構成が選択できることを確認する(待受開始は 5 章で実施)

5. 最小サンプルでブレークポイント確認

public/index.php を作成します。

<?php
declare(strict_types=1);

$userId = 42;
$message = 'Xdebug connected';

// ここにブレークポイント
if ($userId > 0) {
    echo $message . ' user=' . $userId . PHP_EOL;
} else {
    echo 'invalid user' . PHP_EOL;
}

操作順を固定して実行します。

  1. public/index.php を保存する
  2. VS Code で Listen for Xdebug を開始する
    listen for xdebug
  3. ブレークポイントが赤く有効になっていることを確認する
    active breakpoint
  4. ブラウザで http://localhost:8080/index.php を開く(または下記 curl
  5. 停止したら Step Over で進める breakpoint stopped

curl の場合:

curl http://localhost:8080/index.php

成功判定:

  • ブレークポイント行で停止する
  • Variables で $userId / $message を確認できる
  • Step Over で次行へ進める

止まらない場合は 7 章へ進んでください。

6. start_with_request=yes から trigger へ移行する(任意)

常時デバッグを避けたい場合は、xdebug.ini の1行だけ変更します。

-xdebug.start_with_request=yes
+xdebug.start_with_request=trigger

反映:

docker compose restart app
docker compose exec app php -i | grep -E "xdebug.start_with_request"

主線のトリガー方法(クエリ):

curl "http://localhost:8080/index.php?XDEBUG_TRIGGER=1"

trigger に変更した後、トリガーなしアクセスで止まらないのは正常です。

7. よくある詰まりと復旧手順

症状まず確認することよくある原因対処
ブレークポイントで止まらないdocker compose exec app php -ixdebug.mode / xdebug.start_with_request / xdebug.client_port を確認start_with_request=trigger のままトリガーなしでアクセスしている / client_port 不一致まず start_with_request=yes に戻して疎通確認。port: 9003 と合わせる
ブレークポイントが灰色launch.jsonpathMappings と、コンテナ実パスを確認/var/www/html${workspaceFolder} の対応ズレpathMappings"/var/www/html": "${workspaceFolder}" に修正
接続不可(client_host 解決失敗)docker compose exec app getent hosts host.docker.internal名前解決できていない / extra_hosts 未設定extra_hosts: ["host.docker.internal:host-gateway"] を設定して docker compose up -d
VS Code側で待受していないRun and Debug で Listen for Xdebug 実行中か確認設定ミスではなく待受未開始Listen for Xdebug を開始してから再アクセス

トラブル時の再確認コマンド:

docker compose ps
docker compose exec app php -i | grep -E "xdebug.mode|xdebug.client_host|xdebug.client_port|xdebug.start_with_request|xdebug.log"
docker compose exec app getent hosts host.docker.internal
docker compose exec app tail -f /tmp/xdebug.log

8. まとめと次の一歩

次の状態が整いました。

  • 新規デモ環境で Xdebug ステップ実行を再現できる
  • xdebug.ini / launch.json / pathMappings の最小構成を固定できる
  • yes 主線から trigger へ任意移行できる

次の一歩:

  1. VS Codeで始めるPHP開発環境(推奨拡張 + settings.json最小構成) でエディタ基盤を再確認する
  2. VS CodeでPHPコード整形をそろえる(EditorConfig + PHP CS Fixer最小導入) で整形手順を固定する
  3. 実アプリ側の CRUD 実装で、Xdebug を使った調査手順に発展させる

シリーズ 5/5

このシリーズ

PHP開発環境とVS Code

  1. 1. Windows 11で始めるPHPローカル開発環境(WSL2 + Docker + PostgreSQL)
  2. 2. Windows 11でPHP 8.3/8.4/8.5を使い分ける環境構築(WSL2 + mise + Docker Compose)
  3. 3. VS Codeで始めるPHP開発環境(推奨拡張 + settings.json最小構成)
  4. 4. VS CodeでPHPコード整形をそろえる(EditorConfig + PHP CS Fixer最小導入)
  5. 5. VS Code + Xdebugでステップ実行入門(WSL2 + Docker) 現在の記事