Xdebug徹底解説!環境ごとの設定方法から仕組みまでどこよりも詳しく解説します

プロフィール画像

柳下 拓也

2024年08月23日

リンクをコピーXでシェアするfacebookでシェアする

はじめに

はじめまして!
株式会社メンバーズの柳下です。

この記事では、PHPのデバッグツール「Xdebug」の導入方法と基本的な使い方、その仕組みについてどこよりも詳細に解説いたします。これであなたもデバッグマスター間違いなし!敬遠されていた方や仕組みをよく分からず使っていた方はぜひ参考にしてみてください。

Xdebugでできること

まず初めに、Xdebugでは具体的にどんなことができるのでしょうか?開発環境に導入することで以下のことができるようになります。

  • ステップ実行
    • IDE(Visual Studio Code(以下、VSCode)、PhpStormなど)内でステップ実行Open in new tabができるようになります。
  • PHPのエラーレポート表示改善
    • var_dumpの表示やスタックトレースOpen in new tabの表示をデフォルトの味気ないものから、分かりやすく整形した形で表示してくれるようになります。
  • 関数トレース
    • 一連の処理で実行された関数、その関数に渡された引数や戻り値、呼び出された場所などの情報をログに出力することができるようになります。
  • プロファイリング
    • KCacheGrindやWinCacheGrindなどのツールと組み合わせることで、スクリプト内のどこの処理がボトルネックとなっているか可視化できるようになります。
  • コードカバレッジの解析
    • 単体テストのフレームワークであるPHPUnitと組み合わせることで、コードカバレッジOpen in new tabを可視化することができるようになります。

特にステップ実行についてはvar_dumpなどの関数を使ってデバッグを行う場合に比べて、格段にデバッグの効率を上げることができる強力な機能です。是非活用してみてください。

Xdebugの導入方法

ここからは実際にXdebugを導入し、ステップ実行ができるようになるまでの流れを解説します。

開発環境への導入

なお、以降の手順はリモートサーバー上にXdebugを導入する手順です。ローカルマシンがmacOS、リモートサーバーはGoogle Cloud上のGoogle Compute EngineのVMインスタンス(以下環境詳細)で実行・動作検証を行なっております。インスタンスのOSおよびPHPのバージョンは以下の通りです。

# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.4 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

# php -v
PHP 8.3.9 (cli) (built: Jul  5 2024 12:03:23) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.9, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.9, Copyright (c), by Zend Technologies

他ディストリビューションやローカル環境へのインストール等については以下の公式ドキュメントを参考にしつつ進めてみてください。

今回導入する環境の簡単な構成図は以下です。

1. Xdebugのインストール

予め、既にXdebugがインストールされていないか以下のコマンドで確認をしておきましょう。

php -m | grep -i 'xdebug'

特に何も返ってこない場合はXdebugがインストールされていないのでインストールを行います。(既にインストールされていた場合は、必要に応じて手順2または3から実施してください。)

公式ドキュメントを参考にインストールを行います。以下は、今回の検証環境であるUbuntuにパッケージマネージャ経由でXdebugをインストールする際のコマンドです。

# パッケージを更新
sudo apt update

# Xdebugのインストール
sudo apt install php-xdebug

2. 設定ファイル(xdebug.iniまたはphp.ini)の修正

次に、Xdebug用の設定項目を追記します。
PHPが読み込んでいるxdebug.iniファイルのパスは以下のコマンドで確認できます。

php -i | grep 'xdebug.ini'

# 出力結果
/etc/php/8.3/cli/conf.d/20-xdebug.ini,

万が一、xdebug.iniが見つからない場合はphp.iniへ追記してください。同様のコマンドでパスを特定することができます。

php -i | grep 'php.ini'

# 出力結果
Configuration File (php.ini) Path => /etc/php/8.3/cli
Loaded Configuration File => /etc/php/8.3/cli/php.ini # 読み込まれている設定ファイルのパス

注意点として、追記する設定項目はインストールされているXdebugのバージョンによって多少異なる為、現在インストールされているXdebugのバージョンを予め確認しておいてください。バージョンは以下のコマンドで確認できます。

php -v

インストールが問題なく完了している場合は、以下の通りwith Xdebug ... の文言が表示されます。

バージョンに応じてxdebug.iniまたはphp.iniに以下を追記してください。なお、ファイルの所有者がrootになっている場合は、一時的に所有者を変更するか、sudo vim ...などで編集してください。

with Xdebug v2.x.x の場合

[xdebug]
; Xdebugの機能を有効化
xdebug.remote_enable=1
; PHPの実行時にデバッグを自動的に開始する
xdebug.remote_autostart=1
; 接続先ホスト
xdebug.remote_host=localhost
; 接続先ポート
xdebug.remote_port=9003

with Xdebug v3.x.x の場合

; Xdebugの機能の内、ステップデバッグを有効化
xdebug.mode=debug
; PHPの実行時にデバッグを自動的に開始する
xdebug.start_with_request=yes
; 接続先ホスト
xdebug.client_host=localhost
; 接続先ポート
xdebug.client_port=9003

それぞれの項目については公式ドキュメントOpen in new tabをご確認ください。

(詳細については後述しますが、Xdebugが有効になっているPHPは、実行時にここで指定したホスト・ポート宛にDBGpというプロトコルを用いて接続を試みます。その為、ホスト・ポートは接続を待ち受ける側(クライアントのホスト及びIDEで解放するポート番号)の情報を設定する必要があります。今回の例に関しては、Google CloudのVMインスタンス内のPHP・IDE間で通信する想定なのでホストはlocalhostとしています。ポートについてはIDEで設定する値と合わせておけば良いので、9003以外の値でも問題ありません。今回はVSCodeでのステップ実行を想定しているため、VSCodeデフォルトの9003番を指定しています。)

3. IDEの設定を行う

ステップ実行を行う場合はさらにIDE側の設定も必要になります。今回はVSCodeでの設定方法を見ていきます。

まず初めに、ステップ実行を行いたい任意のプロジェクトをVSCodeで開きます。

code ~/path/to/project

(macOSをお使いの場合で、codeコマンドが使えない場合はパスが通っていない可能性があるので公式ドキュメントOpen in new tabを元に適切な設定を行ってください。)
Xdebugを用いたデバッグには公式が出している「PHP Debug」拡張が必要になりますので予めインストールしておきましょう。

次に、サイドバーのデバッグアイコンを押下して(またはcmd+shift+d)、「実行とデバッグ」メニューを開きます。

launch.jsonファイルを作成しますをクリックすると、デバッガー選択プルダウンが出現するので、その中からPHPを選択してください。

(既に何かしらのデバッグ構成が存在していて、launch.jsonファイルを作成しますが表示されない場合は以下の通り、右上の歯車マークでlaunch.jsonを開くことができます。)

するとワークスペース配下に以下のような内容で.vscode/launch.jsonが自動的に作成されます。

~/path/to/project/.vscode/launch.json

{
  // IntelliSense を使用して利用可能な属性を学べます。
  // 既存の属性の説明をホバーして表示します。
  // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
   "version": "0.2.0",
   "configurations": [
       {
           "name": "Listen for Xdebug",
           "type": "php",
           "request": "launch",
           "port": 9003
       },
  // 省略

 基本的にはデフォルトで作成されるListen for Xdebugを使用すれば問題ないかと思いますが、portが他のサービスと重複している場合などあれば適宜変更してお使いください。(launch.jsonのドキュメントOpen in new tab

また、デバッグの構成をグローバルに設定することも可能です。その場合はsettings.jsonに以下のように項目を追加してください。
(settings.jsonは、cmd+shift+pでコマンドパレットを開き、open settings (JSON)と入力して、最上部に出てきたメニューを選択すると開くことができます。)

/Users/ユーザー名/Library/Application Support/Code/User/settings.json

"launch": {
   "version": "0.2.0",
   "configurations": [{
     "name": "Listen for Xdebug",
     "type": "php",
     "request": "launch",
     "port": 9003
   }]
}

4. 実際にステップ実行をしてみよう

では最後に動作検証をしてみましょう。
今回はpaiza等のアルゴリズム問題をデバッグする場合を想定し、PHP実行時にステップ実行が開始することを確認していきます。

まず、実行とデバッグを開きListen for Xdebugの左側の再生マークを押下します。すると、ステップ実行のメニューバーが表示され、先ほど設定したポート番号(今回は9003番)で接続を待ち受ける状態になります。

この状態で、ステップ実行を開始したい箇所に以下のようにブレークポイントを設定します。(行数表示のさらに左側にカーソルを合わせると赤点が表示されるのでクリックしてください。)

ここまで来たら準備完了です。実際にこのPHPを実行してみましょう。

するとあら不思議!プログラムがブレークポイントで一時停止し、該当の行がハイライトされます。この時、実行とデバッグの上部、変数メニューでは該当行実行時に定義されている変数の中身を確認することができます。var_dumpで個別に確認していたこれまでの自分とはおさらばしましょう!

その他、VSCodeのデバッグについてはウォッチ式やコールスタック、デバッグコンソールなど便利な機能がたくさんあります。少し古いですが、こちらの記事Open in new tabに良くまとまっているので、デバッグを極めたい!という方は一度目を通してみることをオススメします。

補足: ステップ実行の種類について

メニューバーから確認できる通り、ステップ実行には3つの種類が存在します。

ステップイン(F11)

最もステップ単位が小さいデバッグ方法です。基本的には1行単位で実行され、実行中に関数が含まれていた場合については、関数内部も1行単位で実行することができます。

ステップオーバー(F10)

ステップインと基本的な動作は変わりませんが、実行中に関数が含まれていた場合については関数内部には入らず、関数実行後の状態(次の行)に移行します。


ステップアウト(shift + F11)

現在実行している関数の残りの処理をスキップします。例えば、ステップインで関数内に入ったものの関数の残りの処理をスキップしたい場合などに使用します。

Docker環境に導入する方法(リモートデバッグ)

ここまではVMインスタンス内にインストールされたPHPにXdebugを導入し、ステップ実行を行う方法を見てきましたが、最近では開発時にDockerを使用することがデファクトスタンダードになっている為、サーバーにインストールしたPHPを直接使用する機会はあまりないかもしれません。そこで、ここではDocker環境でXdebugを使ってデバッグする方法を解説いたします。

Docker環境でXdebugを使用する際は具体的に以下の対応が必要になります。

  1. DockerfileにXdebugインストール用のコマンドを追記
  2. Xdebugの設定を記載したxdebug.iniまたはphp.iniファイルをマウント(またはコピー)
  3. プロジェクト配下に.vscode/launch.jsonを作成

なお、処理が遅くなったりセキュリティ上の懸念があったりするため、案件開発時にXdebugを導入する際は、環境変数で処理を切り分けるなどして、本番環境のPHPにXdebugが紛れ込まないよう十分ご注意ください。

最終的な構成は以下です。

順を追ってみていきます。

1. DockerfileにXdebugインストール用のコマンドを追記

まずは、コンテナ内のPHPにXdebugをインストールするためにDockerfileにXdebugのインストールコマンドを追記しましょう。

# 省略
RUN pecl install xdebug && \
   docker-php-ext-enable xdebug

2. Xdebugの設定ファイルをマウント(またはコピー)

次にXdebugの設定を記載したphp.iniを作成し、それをコンテナ内のPHPが読み込めるようマウント(またはコピー)します。

中身は基本的に前述の内容で問題ありませんが、ホストのみhost.docker.internalにする必要があります。このhost.docker.internalはコンテナ内からDockerホストに通信する際の特別なDNS名です。

with Xdebug v2.x.x の場合

; 接続先ホスト
xdebug.remote_host=host.docker.internal

with Xdebug v3.x.x の場合

; 接続先ホスト
xdebug.client_host=host.docker.internal

なお、Docker for mac や for windows では特別な設定なくhost.docker.internalが利用できるのですが、linuxにインストールされたDockerの場合、docker-compose.ymlに以下の設定を追記する必要がありますのでご注意ください。

# 省略
services:
 app: # host.docker.internalを使用したいサービス名
   build: ./
   extra_hosts:
     - "host.docker.internal:host-gateway"

※さらなる落とし穴として、こちらの設定はversion 20.10.0以降のDockerがインストールされている場合でしか用いることができません。もし古いDockerを使用していて、なおかつなんらかの理由によりバージョンアップなどが難しい場合は以下の記事を参考にしてみてください。

次に、docker-compose.ymlにて設定ファイルをマウント(もしくはDockerfile内でコピー)する設定を追加しましょう。

# 省略
services:
 app:
   build: ./
   extra_hosts:
     - "host.docker.internal:host-gateway"
   volumes:
     - ./path/to/php.ini:/usr/local/etc/php/php.ini # ローカルのパスは任意の値に書き換えてください

Dockerfileでコピーする場合は以下です。

# 省略
COPY path/to/php.ini /usr/local/etc/php/php.ini

3. プロジェクト配下に.vscode/launch.jsonを作成

最後に、プロジェクト配下に.vscode/launch.jsonを作成します。手順は前述の通りです。なお、コンテナ内のパスとホストマシンのパスとを対応させる為、追加でpathMappingsという項目を追加します。pathMappingsは コンテナ内のルートディレクトリ: ホストのルートディレクトリ の形式で記載してください。その際、${workspaceRoot}などの変数も利用できます。

~/path/to/project/.vscode/launch.json
"configurations": [
   {
       "name": "Listen for Xdebug",
       "type": "php",
       "request": "launch",
       "port": 9003
       // 以下は環境に応じて書き換える
       "pathMappings": {
             "/var/www/html": "${workspaceRoot}/path/to/html"
       }
   },

これでDocker環境でXdebugが使えるようになりました。なお、設定変更後は念のため一度ビルドしなおしてからコンテナを起動してください。ステップ実行の手順は前述の内容を参考にしてください。

# キャッシュを使わないでビルド
docker-compose build --no-cache app
# コンテナ起動
docker-compose up -d

Xdebugを用いたステップ実行の仕組みについて

ここまで各環境ごとの導入方法と、VSCodeを用いたデバッグの方法について解説してきました。ただ、「いまいちどういう仕組みで動いてるか分からん」となってる方もいらっしゃるかと思いますので、最後に、公式ドキュメントOpen in new tabを元にXdebugのステップ実行の仕組みについて解説いたします。こちらを理解していると、開発環境やIDEが変わってもXdebugの導入に手こずらなくなるかと思います。

公式ドキュメントには以下のように記述されています。

> Xdebug interacts with IDEs to provide step debugging functionality, and therefore you also need to configure an IDE that knows how to talk to Xdebug with the open DBGp protocol.

訳すと、
> XdebugはIDEと連携してステップ実行機能を提供します。その為、DBGpプロトコルでXdebugと対話可能なIDEに対しても設定を加える必要があります。
といった感じです。

ここで出てくるDBGpとは、Xdebug(PHP)とIDEが相互に通信を行う際に用いられる通信プロトコルのことです。先に軽く触れた通り、XdebugがインストールされたPHPは、実行時にDBGpプロトコルでphp.iniにて追記したホスト・ポート宛に通信をおこないます。その際、IDE側で通信を待ち受け、受信に成功するとIDE側で内容に応じた処理を行うことができるようになります。

少し分かりにくいかと思いますので、公式が用意してくれている図を用いて説明します。前提として、この図ではPHPを用いたWebシステムをデバッグする際の流れになっています。こちらを元にステップ実行の流れを説明すると、

  1. クライアント(画像左側、IPアドレス = 10.0.1.42)がブラウザ等を経由してサーバー(画像右側、IPアドレス = 10.0.1.2)にHTTPでリクエストを投げます。(この時クライアント側は、IDEの機能を用いてポート9000番で通信を待ち受けている状態です。)
  2. リクエストを受け付けたサーバーは、リクエストに応じたPHPファイルを実行します。サーバーのPHPにはXdebugがインストールされている為、php.iniに記載したクライアント(IPアドレス = 10.0.1.42, ポート番号 = 9000)にDBGpプロトコルを用いてデバッグ情報を送信します。
  3. クライアントはサーバーからのDBGp通信を受け取り、以降IDE内での実行内容(ブレークポイントでの停止、ステップ実行、停止、再起動など)に応じてサーバー側とDBGpプロトコルを用いて相互に通信をおこないます。
  4. ステップ実行が終了したら、最後にサーバーはクライアントにHTTPでレスポンスを返します。

いかがでしょうか?Xdebugを用いてステップ実行する際のクライアント・サーバー間の通信の流れがご理解いただけたのではないかと思います。

最後に

この記事では、PHPのデバッグツール「Xdebug」の概要や導入方法、使い方やその仕組みについて出来る限り詳しく解説いたしました。自分が最初にXdebugと出会った時は、訳が分からず挫折しかけた思い出があるので、そんな方の一助になれば幸いです。

最後まで読んでいただきありがとうございました。それでは、素敵なデバッグライフをお楽しみください!

この記事を書いた人

柳下 拓也
柳下 拓也
神戸出身のWebエンジニア。文学部卒のド文系ですが、IT好きが高じてエンジニアにキャリアチェンジしました。
ページトップへ戻る