Dev Containersファイル作成後から。最後に、デバッグ構成ファイルを作成する。
launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
}
}
]
}
以上でデバッグ環境が構築されている。
"pathMappings"については、Apache(サーバー)のドキュメントルートとプロジェクトのフォルダ構造をVSCodeに教えるための項目。デフォルトが"pathMappings": { "/var/www/html": "${workspaceFolder}" }なので、書く必要はないが理解しやすいように残している。
/var/www/html/virtual/test/public_html/testphp.coresv.comというディレクトリ構成ゆえに、変更が必要かと思いきや、ルートのphpも/var/www/html/virtual/test/public_html/testphp.coresv.com/index.phpにあるので、変更の必要はない。
分かればシンプルな話なのだけど、docker-compose.ymlの以下の項目。
services:
app:
volumes:
# 親フォルダ(..)をコンテナ内の /var/www/html に同期する
- ../:/var/www/html:cached
(.devcontainer/内の)docker-compose.ymlのvolumes設定で、プロジェクトの親フォルダ(ワークスペース直下)をコンテナの/var/www/htmlに丸ごとマウントしている。そのため、コンテナ内のディレクトリ構造と、VSCode上のフォルダ構造が完全に一致していて、デフォルトのpathMappingsだけでパス解決はできている。
root@ffee28f3ebc9:/var/www/html# ls .devcontainer
Dockerfile devcontainer.json docker-compose.yml post-start.sh
次にDockerfileは、以下のとおりになっている。
ENV APACHE_DOCUMENT_ROOT /var/www/html/virtual/test/public_html/testphp.coresv.com
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf
なので、ブラウザでURL
http://testphp.coresv.com にアクセスすると、コンテナの/var/www/html/virtual/test/public_html/testphp.coresv.com/index.phpを見に行く。VSCodeでも${workspaceFolder}/virtual/test/public_html/testphp.coresv.com/index.phpと一致するので、問題なくデバッグできる。
もし、Apacheを使わない場合、php -S1を使ったビルトインの簡易webサーバを起動して、デバッグを行うするときは、調整が必要かも知れない。
以下、デバッグできなかった場合の探り方を書き残しておく。
デバッグできない!!!
最初、デバッグできなくて困った。
結論から言ってしまうと…渡されたソースが、構築した環境では致命的エラーとなるため、デバッグする前に処理が終了していた。
詳しく説明すると親クラスがいないextendsしていないのにparent::execute($sql, $bindArr);をしていて、当然親クラスがいないので、エラーとなる。
しかし、私はphpはインタプリタ型言語だから、エラー箇所を通らなければエラーは起きないと思っていた。また、現行機が問題なく動いているのだから、このソースで動くはずだ、と思い込んでいた。
しかし、PHP7.0以降、includeしたタイミングでチェックして、エラーを出すようになったらしい。
何故、デバッグできないかを探求する
まずは、止めたい場所にxdebug_break();を埋めこんでみる。でも止まらない。
Xdebugオプションとして-dxdebug.log=/tmp/xdebug.logを追加する。デバッグログファイルがない場合は、Xdebugが起動できてない。
ログの中身を見ると、Xdebug: [Step Debug] Could not connect to debugging client. Tried: localhost:9000 (through xdebug.client_host/xdebug.client_port).となっている。
接続できていない。ipやポートなどのズレ。-dxdebug.client_host=127.0.0.1、-dxdebug.client_port=9003などのオプションを追加する。そして、launch.jsonの"port": 9003,と合わせる。この状態だとデバッグログを見ずともコンソールに出力されている。
次に、以下の内容がデバッグログに出力された。
[1354] [Step Debug] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="run" transaction_id="13" status="stopping" reason="ok"></response>
[1354] [Step Debug] <- stop -i 14
[1354] [Step Debug] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stop" transaction_id="14" status="stopped" reason="ok"></response>
[1354] Log closed at 2026-02-01 09:13:58.167478
stoppingとあるので、ブレークポイントが無視されて、最後までプログラムが実行されている。file://を出力している箇所を探す。
<notify xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" name="error"><xdebug:message filename="file:///var/www/html/virtual/test/public_html/testphp.coresv.com/noParents.php" lineno="165" type="Fatal error"><![CDATA[Cannot use "parent" when current class scope has no parent]]></xdebug:message></notify>
エラーとなっている行、Cannot use "parent" when current class scope has no parentという原因が分かる。
ああ、勘違い
動かせば、普通にエラーは出るので、知ってはいた。 繰り返しになるが、インタプリタ型言語だから、そこが実行されなればいいはずと勘違いしていた。
「現行機(古いPHP)では動いているのだから、コードに致命的な間違いはないはず」
「現行機でエラーが起きないのは、そもそもその処理を通っていないからだ」
「それなのに、デバッグ機(新しいPHP)ではエラーが出力される。ということは、なぜかそこを通ってしまっている」
「どうして通ってしまうのか分からない。よし、デバッグして実行ルートを追いかけよう」
「……あれ? デバッグできない(ブレークポイントで止まらない)」
しかし実際は 、通る・通らない以前に、PHP8.4がファイルを読み込んだ瞬間に構文チェックで致命的エラーを出して死んでいた。そのため、Xdebugがブレークポイントで止まることなく、プロセスが終了していた。
ソースを修正しないでデバッグできない原因を探ろうとして、あれこれ設定ファイルをいじったり、ファイヤウォールを開けたり迷走を繰り返した。しかし、こうやって、デバッグできない原因として出ているので、これはソースの修正がいると確信した。
ちなみにpathMappingsがおかしいと、[4962] [Step Debug] WARN: Breakpoint file name does not exist: /var/www/html/virtual/test/public_html/testphp.coresv.com/virtual/test/public_html/testphp.coresv.com/index.php (No such file or directory).と存在しないパスが出力されるので、ズレていると分かる。
ちゃんと理解しないでgeminiに質問すると、前提条件をちゃんと伝えてないから、その場しのぎの回答をしてきて、不要な修正をしてしまったりする。とはいえ、ググることなく、ここまで辿りつけたのもgeminiのおかげだ。
それでは、よりよい開発環境を!
-
php8.4イメージのときはphp -dxdebug.mode=debug -dxdebug.start_with_request=yes -dxdebug.client_host=127.0.0.1 -dxdebug.client_port=9003 -S 0.0.0.0:8000 -t ${workspaceFolder}/virtual/test/public_html/testphp.coresv.comでデバッグしてた。なので"pathMappings"は同じく設定不要だった。 ↩︎