どうもこんにちは、カフーブログのタカフです。
ローカル開発環境でVSCode+Docker+WSL2でPHPのステップ実行のデバッグ実行したい時ってありますよね。
ですが、最近の主流である
- VSCode
- Docker(php:8.x)
- WSL2 上のプロジェクト
という構成では、 Xdebug が接続できない/ブレークポイントで止まらない問題が頻発 しがちです。
大抵その原因のは、
「Xdebug の接続方向」と「WSL2 のデバッグ開始リッスンの張り方」
だったりします。
そこで本記事では、
- VSCode(WSL2)で PHP プロジェクトを開き
- Docker コンテナ内の PHP と Xdebug を連携させ
- ステップ実行できるようにする
という一連の手順を まとめて解説していきたいと思います。
準備
それではVSCodeでDocker + PHP + Xdebug環境のデバッグ実行するための準備をすすめていきます。
Xdebug用のphp.iniファイルを用意
まずDockerのPHPコンテナに入れるXdebug用のphp.iniファイルを用意します。
Xdebug用の設定ファイルなので、設定ファイルはphp-xdebug.iniとでもしておきましょう。
今回はXdebug version3以降の設定をします。最低限必要な記述は以下です。
[xdebug]
xdebug.mode=debug,develop
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.start_with_request=yes
xdebug.mode
まずxdebug.modeでxdebugの中でもどの機能を使うかを指定します。
デバッグといえばまずはステップ実行がしたいのでdebugが必要です。あとオススメはvar_dump()を見やすく表示してくれるdevelopです。複数指定の時はカンマ区切りで表します。
他にもモード以下の通りであり、必要に応じてカンマ区切りで追加するとよいでしょう。単体テストとかするときはcoverageとか使いたいですね。
| モード名 | 主な機能 | 使う目的・場面 |
|---|---|---|
off |
Xdebugを無効化(何もしない) | 本番環境など、パフォーマンスを重視したい時 |
develop |
var_dump() の見やすい表示、詳細なエラー表示 |
ふだんの開発でちょっと便利にしたい時 |
debug |
ステップ実行・ブレークポイント・変数ウォッチ | VSCodeやPhpStormで本格的にデバッグする時 |
trace |
関数の呼び出し順や引数・戻り値を記録 | 処理の流れを詳しく追いたい時 |
profile |
処理時間・CPU使用などを記録(KCacheGrind対応) | 処理が遅い原因を調べたい時 |
coverage |
テストのコードカバレッジ(網羅率)測定 | PHPUnitなどでテストの範囲を確認したい時 |
gcstats |
メモリのガーベジコレクション統計を記録 | メモリ管理やGC動作を分析したい時 |
xdebug.client_host, xdebug.client_port
Docker版PHPでXdebugを実行するときに重要なのがこの設定です。
Docker の PHP コンテナは Xdebug でデバッグを開始すると、
VSCode(=デバッグクライアント)へ TCP 接続を行います。
接続方向はこうです。
Docker(PHP) → VSCode(Windows)
そのため、xdebug.client_host には VSCode が動く ホスト側の IP を指定する必要があります。
Docker for Windows では host.docker.internal でホスト側の IP に解決されるため、これを使うのが最も適しています。さらにxdebug.client_portでポートも指定します。Xdebugの標準では9003です。
絵としてはこんな感じになります。

xdebug.start_with_request
これをyesにするとWebページリクエストのPHP実行時に常時デバッグ開始実行します。
以前これを設定していると重くなるイメージがありましたが、今試しているとそんなに重くないと感じたのでこれはyesにしていてよいと思います。
こうすることでデバッグ開始する時に特別なパラメータなどが必要なくなります。
DockerfileでXdebugをインストール
次にDockerfileにXdebugをインストールする記述をしていきます。
peclコマンドでxdebugをインストールするのとxdebugを有効にする記述を書きます。しかしXdebugドキュメントによるとpeclは今は非推奨らしいので、aptやyumのパッケージで入れるのがいいかもしれません。
そして上記で用意したphp-xdebug.iniファイルを置いたら読み込んでくれるphp/conf.dに配置します。
FROM php:8.4-apache
# Xdebugをインストール
RUN pecl install xdebug-3.4.7 && \
docker-php-ext-enable xdebug
# カスタムPHP設定ファイルをコピー
COPY php-xdebug.ini /usr/local/etc/php/conf.d/php-xdebug.ini
ここで重要なのは、PHPのバージョンに合わせてxdebugのバージョンを書くことです。そうしないと常に最新のxdebugがインストールされてコンテナイメージのPHPバージョンと合わなくなるからです。
因みにサポートされているバージョンはxdebugのサイトに記載があります。
https://xdebug.org/docs/compat

例えば、上記を例にするとコンテナイメージはphp8.4なのでそれに合うのは3.4ですが、3.4だけの記述だとDockerのビルド中に以下のようなエラーが出ます。
> [2/7] RUN pecl install xdebug-3.4 && docker-php-ext-enable xdebug:
3.668 Failed to download pecl/xdebug, version "3.4", latest release is version 3.4.7, stability "stable", use "channel://pecl.php.net/xdebug-3.4.7" to install
なので、第3小数点のパッチバージョンまで指定してあげます。
xdebugのリリースページを見れば、これまでのバージョン一覧が列挙してあるのでそれを参考にします。3.4であればその最新パッチバージョンを指定すればよいでしょう。今回は xdebug-3.4.7 まで書いてあげます。
そして、docker-php-ext-enable xdebugのコンテナ上に以下のファイルを設置するだけの処理です。
/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
中身はzend_extension=xdebug.soの1行が書いてあげるだけです。これまでphp.iniの方にこの記述を書くことが多かったですが、Docker版PHPの場合はdocker-php-ext-enableの記述をすればよいでしょう。
Xdebug起動確認
Dockerfileが書けたらコンテナを起動してみます。そして、Xdebugがインストール&動作しているかどうかを確認します。
Webページで確認する場合は何かしらのphpファイルで以下を記述してページ表示すればよいです。
<?php
phpinfo()
Webページで開くとphpinfoの内容が表示され、xdebugで検索すると設定があるのが確認できます。xdebug.mode=debug,developとしているのでStep Debuggerがenabledになっています。

ちなみにコマンドラインでも確認できます。こっちの方が簡単です。phpのコンテナにログインして php -vを実行すればよいです。with Xdebug v3.4.7の文字列が表示されればOKです。
# php -v
Cannot load Xdebug - it was already loaded
PHP 8.4.14 (cli) (built: Nov 4 2025 04:08:35) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.4.14, Copyright (c) Zend Technologies
with Xdebug v3.4.7, Copyright (c) 2002-2025, by Derick Rethans
with Zend OPcache v8.4.14, Copyright (c), by Zend Technologies
この時、もし Cannot load Xdebug - it was already loadedと表示される場合は、zend_extension=xdebugを2回ロードしていることが原因です。
大抵どこかのphp.iniファイルにzend_extension=xdebugが書かれてあるのでそれを削除すれば問題解消されます。
VSCodeにlaunch.jsonを用意
上記まででXdebugの実行側は準備が整いました。次にVSCode側です。
以下のような記述をします。
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"hostname": "0.0.0.0",
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
"log": true
}
]
}
ここで重要なのは"hostname": "0.0.0.0" です。これはすべてのネットワークインターフェースで待ち受けるという指定になります。
WSL2 環境では
- VSCode(Windows 側)
- Docker(WSL or Windows)
- PHP コンテナ(独立ネットワーク)
がすべて別ネットワークとして扱われます。
そのため VSCode は localhost のみで待ち受けていると
WSL2 → Windows への接続(192.168.x.x など)が届かないのです。
hostname": "0.0.0.0" を設定しておくことで、 Windows のすべての NIC(LAN, WSL仮想NIC, Docker仮想NIC)で待ち受けできるようになり、 Xdebug の接続が可能となります。
Docker + PHP のデバッグ実行はここがハマりポイントなんですよね。
幸いなことにWindowsフォルダとして開く時も"hostname": "0.0.0.0" と書いておけば対応できるので、Docker + PHPでXdebug実行環境つくるときはとりあえずこれ書いておけばOKかと思います。
あともう一つ重要なのは、以下ですね。
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
コンテナ上のプロジェクトディレクトリ位置と、ホストマシン側のプロジェクトディレクトリを位置を合わせておく必要があります。
"/var/www/html"はコンテナ側のドキュメントルートですね。上記であればphp:8.4-apacheのコンテナイメージに従って記述します。
"${workspaceFolder}"は、ホストマシン側のパスに自動で置き換わってくれます。
PHP Debugのインストール
VSCodeの拡張で「PHP Debug」をインストールします。WSLでプロジェクトフォルダを開いている場合はWSL上でインストールが必要です。

Xdebugのデバッグ開始
上記までの準備が整っていればあとは簡単です。
例えば”Hello World.”と出力するだけのPHPコードがあるとします。その変数代入の3行目でブレークポイントを貼ります。

そして左メニューで実行表示にしてデバッグ開始の緑色の右三角ボタンを押します。そうするとデバッグリッスン状態になり、エディタ真ん中に停止ボタンなどが現れます。

ここで実際にそのphpファイルを表示させるファイルにアクセスしてみます。
そうするとブレークポイントの行で止まります。xdebug.start_with_request=yesを設定してるので常時デバッグ実行しているためブレークポイントなど貼っていれば止まります。

F10キーで1ステップ進みます。ローカル変数 $varに”Hello World.”が入るのがわかります。

そのままF5キーで続行するとページ表示されます。便利ですね~。

コマンドライン実行時も同じ設定でデバッグ実行できます。
今回はdocker composeで環境作ってますので、docker composeから直接コマンド実行してみます。appというサービス名にしてるので、以下のコマンドでコンテナ内のphpをCLI実行します。
$ docker compose exec app php /var/www/html/test.php
先ほど同様ブレークポイントで止まります。

F5で実行を続けるとターミナル上で”Hello World.”が出力されます。
コマンドラインでのデバッグ実行も以前は環境変数で開始が必要だったりしましたが、xdebug.start_with_request=yesしていれば常時デバッグ実行になるので楽ですね。
Tips
今回この記事を書く際に困ったポイントも残しておきます。
デバッグ実行できない時は
Xdebugでデバッグ実行できない時はまずXdebug側のログをみるとわかりやすいです。
上記のphp-xdebug.iniに以下を追記してxdebug側のログを有効にします。
xdebug.log=/tmp/xdebug.log
xdebug.log_level=7
そうすると/tmp/xdebug.logでXdebugのログを確認できます。Xdebugが何かしら動いていればこのログファイルが生成されます。
例えば、以下のログの場合はXdebugとして実行してhost.docker.internal:9003に接続しにいっているが、その接続先が見つからないパターンです。
# tail -f /tmp/xdebug.log
[17] Log opened at 2025-11-09 05:15:07.660027
[17] [Step Debug] INFO: Connecting to configured address/port: host.docker.internal:9003.
[17] [Step Debug] WARN: Creating socket for 'host.docker.internal:9003', poll success, but error: Operation now in progress (29).
[17] [Step Debug] ERR: Could not connect to debugging client. Tried: host.docker.internal:9003 (through xdebug.client_host/xdebug.client_port).
[17] Log closed at 2025-11-09 05:15:07.663463
最初僕も接続できなくて悩まされましたがこのログを見てクライアント側がちゃんとリッスンできてないからでは?と気づきました。そして上述の通りWSL2でプロジェクトファイルを開いている場合は"hostname": "0.0.0.0"を書くことで無事リッスンできて接続されるようになりました。
変数の値が全部表示されない時は
VSCodeでXdebugのデフォルト設定だと長い文字列の場合、ローカル変数表示で全て表示してくれません。PHPStormの時は常に全部表示されていたのですがそれはPHPStorm側のデフォルト設定なのかもしれません。
というわけ長い文字列などの変数の値を全部表示したい時はlaunch.jsonでxdebugSettingsを追記します。max_dataで1つの変数の文字数上限を設定することができます。
{
"version": "0.2.0",
"configurations": [
{
"name": "Webデバッグ",
"type": "php",
"request": "launch",
"port": 9003,
"hostname": "0.0.0.0",
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
"xdebugSettings": {
"max_children": 128, // 配列/オブジェクトの子要素数
"max_data": 60000, // 1 つの変数の文字数上限(ここを増やす)
"max_depth": 5 // ネストの深さ
// 必要なら "show_hidden": 1 なども
},
"log": true
}
]
}
まとめ
以上、VSCode + Docker + PHP環境でXdebugを実行する手順でした。
最近ではPHPのローカル開発環境はこの構成がスタンダードになりつつあるので、Xdebugの方法についてしっかりと理解して覚えておくと実際の開発作業が困らなくなりますね。
現場からは以上です!
