Xdebug の使い方

2021/09/19

PHPでの開発効率を向上させるために、PHP自体に機能を追加するという方法があります。

Xdebug とは?

Xdebug は、PHPでの開発効率を向上させるためのさまざまな機能を提供してくれるPHPの拡張機能(エクステンション)です。 Xdebug でできることは下記の6つです。

  • ステップ実行:スクリプトの実行中にIDEまたはエディターでコードをステップ実行
  • 開発ヘルパー:var_dump() 関数の拡張、スタックトレース表示の拡張
  • 関数トレース:すべての関数の呼び出しを追跡してファイルに保存
  • プロファイリング:PHPアプリケーションのパフォーマンスを分析
  • ガベージコレクション統計:PHPの内部ガベージコレクターの統計を確認
  • コードカバレッジ解析:PHPUnit でテスト対象のコードがどれくらいテストされたかを解析

Xdebug のインストール

Xdebug をインストールする方法はいろいろありますが、ここでは Windows の XAMPP 環境にインストールする方法を紹介します。

Xdebug をダウンロードする

Xdebug はPHPの拡張機能(エクステンション)です。 Windows の場合は .dll ファイルになります。

公式サイトのダウンロードページから、環境にあった .dll ファイルをダウンロードします。 ベータ版もありますが、ちゃんと動きませんので、安定版(betaとついていないもの)がオススメです。 間違ったバージョンをダウンロードしてしまうと動きませんので注意してください。

download.png

どのバージョンをダウンロードすればいいかわからない場合

どのバージョンをダウンロードすればいいかわからない場合は、Xdebug の公式サイトに調べてくれるページがありますので、それを使ってみましょう。 便利ですが、使い方はかなり特殊です。

  • まず、動作させたい環境で phpinfo() を表示します(コマンドラインから php -i でも良いです)。 その結果を、まるごとコピーします。

    phpinfo.png
  • そしてその内容を公式サイトの Installation Wizard のページに貼り付けて、「Analyse my phpinfo() output」ボタンを押します。

    wizard.png
  • すると、一致しているバージョンを教えてくれるので、その .dll ファイルをダウンロードします。

    instructions.png

PHPの拡張機能として設定する

.dll ファイルがダウンロードできたら、その .dll ファイルをPHPの拡張機能として読み込むよう設定します。

  • まず、ダウンロードした .dll ファイルをPHPのエクステンションディレクトリ("C:\xampp\php\ext")に移動させます。

  • ファイル名を "php_xdebug.dll" に変更します(つまり、"C:\xampp\php\ext\php_xdebug.dll" とします)。

  • 次に、php.ini ファイルを編集し、zend_extension=xdebug の行を追加します。 この際、zend_extension=opcache の行より下に追加するようにしてください。

    php.ini
    zend_extension=xdebug
    
  • 最後にWebサーバーを再起動します。

インストールできたか確認する

Xdebug がインストールできたら、phpinfo() に Xdebug の情報が追加で表示されていますので確認してみましょう。

phpinfo_with_xdebug.png phpinfo_with_xdebug2.png

xdebug_info() 関数

ちなみに、Xdebug がインストールされると、Xdebug の情報を表示する関数、xdebug_info() も使用できるようになっています。 phpinfo() にも同様の内容が表示されていますが、phpinfo() には他の情報も大量に表示されていますので、 Xdebug だけの情報が知りたい場合は xdebug_info() の方が見やすいと思います。

xdebug_info.png

モード

Xdebug ではいろんな機能が使用できますが、それらの機能は全て有効になっているわけではありません。 各機能は、それぞれ有効/無効を切り替えることができます。 つまり、使いたい機能がある場合は、その機能を個別に有効化する必要があります。 機能ごとの有効/無効(モード)は、php.ini で、xdebug.mode という設定項目で変更できます。 複数の機能を同時に有効にしたい場合はカンマ区切りで指定します。 php.ini を変更した場合は、Webサーバーの再起動が必要ですので注意してください。

説明
off 全ての機能を無効にする
debug 「ステップ実行」機能を有効にする
develop 「開発ヘルパー」機能を有効にする
trace 「関数トレース」機能を有効にする
profile 「プロファイリング」機能を有効にする
gcstats 「ガベージコレクション統計」機能を有効にする
coverage 「コードカバレッジ解析」機能を有効にする
開発ヘルパー(develop)とステップ実行(debug)を有効にする場合
php.ini
[xdebug]
xdebug.mode=develop,debug

どの機能が有効になっているか確認する

どの機能が有効になっているかは、phpinfo()xdebug_info() を表示した際に、「Enabled Features」欄に表示されているので、そこでも確認できます。

mode.png

開始タイミング

Xdebug では、いろいろな機能がありますが、それらはすべてのHTTPリクエスト時に常に開始されるようにはなっていません。 全ての機能がすべてのHTTPリクエストで開始されているとパーフォーマンスの観点からあまりよろしくないからです。 必要なタイミングで必要なものだけ開始するという設定になっているのです。

どの機能がどのタイミングで開始するかは xdebug.start_with_request で設定できます。 しかしながら、機能ごとに細かく設定できるわけではなく、Xdebug 全体の設定になりますので、変更すると全ての機能の開始タイミングに影響が出ます。 設定できる値は下記の4つです。思ったタイミングで動かなかったり、動いてしまったりする場合は、この値を確認してください。

  • yes:全てのHTTPリクエストで開始する
  • no:全てのHTTPリクエストで開始しない
  • trigger:条件を満たしたHTTPリクエスト(トリガー)でのみ開始する
  • default:各機能ごとに異なったデフォルト設定とする
    機能 デフォルト設定
    ステップ実行 trigger
    開発ヘルパー (影響なし)
    関数トレース trigger
    プロファイリング yes
    ガベージコレクション統計 no
    コードカバレッジ解析 (影響なし)

例えば、上記のデフォルト設定(xdebug.start_with_request=default)だと、「プロファイリング」機能は全てのHTTPリクエストで開始され、 「ステップ実行」「関数トレース」機能は条件を満たしたHTTPリクエストが送信されたときだけ開始され、 「ガベージコレクション統計」機能はHTTPリクエストでは開始されないので、関数を自分で呼び出すなど、別の方法で開始する必要がある、ということです。

条件を満たしたHTTPリクエスト(トリガー)

条件を満たしたHTTPリクエストの場合のみ開始される設定がトリガーです。 トリガーの条件は、$_ENV$_GET$_POST$_COOKIE のいずれかに XDEBUG_TRIGGER という名前の値があることです。

古いバージョンの Xdebug では、XDEBUG_TRIGGER の代わりに、 XDEBUG_SESSION(ステップ実行用)、XDEBUG_PROFILE(プロファイリング用)、XDEBUG_TRACE(関数トレース用)が使用されていたため、 互換性のためそれらも使用することができるようです。

GETパラメーターをトリガーにする

GETパラメーター($_GET)でトリガーさせる方法は簡単です。 URLのGETパラメーターとして XDEBUG_TRIGGER を付けて、Webブラウザからアクセスするだけです。 GETパラメーターが1つ以上ある場合は、? ではなく & で繋ぎます。

例:
https://example.com/hoge/hoge?XDEBUG_TRIGGER

Cookie をトリガーにする

GETパラメーターをトリガーにする方法は簡単ではありますが、画面遷移が必要な場合や Ajax などを使用している場合は難しくなってきます。 リンクやボタンをクリックするたびに必要になるのですから、それは面倒になってくると思います。 しばらくの間、続けてトリガーさせるためには、Cookie($_COOKIE)からトリガーさせた方が楽です。 そのためのWebブラウザの拡張機能がありますので、それを使うと便利です。

xdebug_helper.png

ステップ実行(モード:debug)

この機能は、PHPスクリプトの実行中にIDEまたはエディターでコードをステップ実行ができるようになるものです。 PHPスクリプトを1行ずつ実行したり、実行中に一時停止させて、その時点の変数の内容を確認したりといったようなことができます。 PHPはWebサーバー上で動作していて、WebブラウザとはHTTPで通信しているため、ステップ実行は難しいのですが、それを可能にしてくれます。 PHPのIDEやエディターはいろいろありますが、ここでは Visual Studio Code(以下、VSCode)を使った方法を紹介します。

VSCode の設定

VSCode の設定で必要なことは下記の2つです。

拡張機能「PHP Debug」をインストール

Xdebug はWebサーバー上で動いていますので、VSCode は通信を行う必要があります。 そのため、VSCode に拡張機能を追加する必要があります。この拡張機能が Xdebug と通信してくれます。 Xdebug の公式でオススメされてるのは Felix Becker さんの「PHP Debug」という拡張機能です。 拡張機能の検索欄に「php debug」と入力して検索しインストールします。 同じ名前の拡張機能がたくさんあるので間違えないよう注意です。

vscode.png

launch.json を作成する

launch.json が無い場合は作成します。無い場合は自動で作ってくれます。

launch_json.png

手動で編集する場合は、下記の内容にします。 プルダウンの「構成の追加」から「PHP: Listen for Xdebug」を選択して追加したのと同じ内容です。

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
        }
    ]
}

Xdebug の設定

VSCode の拡張機能「PHP Debug」のドキュメントには、xdebug.start_with_requestyes とし、全てのHTTPリクエストで開始するよう Xdebug を設定すると記載されていますが、これは必須ではありません。 yes としてしまうと、ステップ実行機能以外の他の機能の開始タイミングにまで影響が出てしまうので注意してください(他の機能を使わないということであれば yes で問題はありません)。

ステップ実行機能の開始タイミングはデフォルトではトリガーです。 ステップ実行時のHTTPリクエストでトリガーできてれば良いだけです。 ブラウザに Xdebug の拡張機能を入れている場合は、Cookie でトリガーさせるのは簡単にできると思いますので、xdebug.start_with_requestdefault のままで問題ありません。 本当に必要なことは、モードを有効にすることだけです。

php.ini
[xdebug]
xdebug.mode=debug

あまり他の機能を使わず、ブラウザに Xdebug の拡張機能を入れるのが面倒で、常にステップ実行できる状態としたいのであれば、xdebug.start_with_requestyes としても問題ありません。 用途に合わせて設定しましょう。

php.ini
[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes

ステップ実行を行う

準備できたので実際にやってみます。 流れは下記になります。

  • VSCode で、一時停止させたい個所にブレークポイントを付ける
  • VSCode で、デバッグを開始(F5)する。その際、launch.json に作成した「Listen for Xdebug」を使用する
  • Webブラウザの Xdebug の拡張機能で、ステップ実行(Debug)のトリガーを有効にする
    xdebug.start_with_requestyes の場合は不要)
  • Webブラウザで、ブレークポイントを付けた個所のURLにアクセスする
step.png

開発ヘルパー(モード:develop)

この機能は、PHPの組み込み関数を拡張し、より多くの情報を取得できるようになるものです。 具体的には、下記の3つが有効になります。

  • var_dump() 関数の拡張
  • Notice、Warning、Error、例外発生時にスタックトレース表示
  • PHPの動作を微調整するための多数の関数と設定

var_dump() 関数の拡張

PHPの組み込み var_dump() 関数の出力がHTML形式に変更され色が付くようになります。 また、呼び出し場所のファイル名と行番号が含まれるようになります。

出力内容
C:\Users\Test\develop.php:22:
array (size=4)
  'one' => string 'a somewhat long string!' (length=23)
  'two' =>
    array (size=2)
      1 => int 1
      2 => int 2
  'three' =>
    array (size=1)
      'foo' => string 'bar' (length=3)
  'four' =>
    object(Test)[1]
      public 'pub' => boolean false
      private 'priv' => boolean true
      protected 'prot' => int 42

表示/非表示の出力量の設定

拡張された var_dump() 関数の出力はHTML形式にはなりますが、それに伴って出力される量に制限がかかるようになります。 例えば、長すぎる文字列や、長すぎたり、深すぎたりする配列やオブジェクトは、省略記号 "…" で省略されるようになります。 これは、メモリ不足に陥らないための措置ではありますが、見たいと思っていた個所の値が見れなくなってしまうという欠点があります。 デフォルト値のままだとかなり困ると思いますので、メモリ不足に陥らない範囲で調整しましょう。 出力される量に関する設定は下記があります。

  • xdebug.var_display_max_data
    文字列が切り捨てられ、省略記号 "…" で表示される前の文字列の長さを制御します。
    デフォルトは 512、無制限は -1 です。
  • xdebug.var_display_max_children
    表示される配列要素またはオブジェクトプロパティの数を制御します。
    デフォルトは 128、無制限は -1 です。
  • xdebug.var_display_max_depth
    データ構造情報の深さ(ネスト)の数を制御します。
    デフォルトは 3、最大は 1023 で、-1 を指定すると最大 1023 と同じになります

PHP_CodeSniffer を使っている場合、xdebug.var_display_max_childrenxdebug.var_display_max_depth の両方を大きい値(もしくは -1)に設定すると、 PHP_CodeSniffer の処理速度がかなり遅くなってしまい、まともに使用できなくなってしまうので注意してください。

php.ini
[xdebug]
xdebug.mode=develop
xdebug.var_display_max_data=512
xdebug.var_display_max_children=128
xdebug.var_display_max_depth=3

スタックトレースの表示

Notice、Warning、Error、例外発生時に、スタックトレースが表示されるようになります。 スタックトレースには、スクリプトの開始からエラーが発生した場所までの間に呼び出されたすべての関数とメソッドのリストが含まれています。

stack.png

PHPの動作を微調整するための多数の関数と設定

開発ヘルパー機能が有効になっている場合のみ使える関数があります。 主にどこで関数が呼ばれているのか調べたり、処理時間を調べたり、メモリ使用量を調べたりするような関数です。 どんな関数や設定があるのかは、ここでは記載しません。 大量にありますので、英語ですが公式のドキュメントを見てもらった方が良いと思います。

関数トレース(モード:trace)

この機能は、すべての関数の呼び出しを追跡してファイルに保存できるというものです。 PHPアプリケーションの実行中に何が起こっているのかを正確に把握しようとしている場合に役立ちます。

.xt ファイル
TRACE START [2021-09-18 11:28:18.886632]
    0.0064     365808   -> {main}() C:\Users\Test\trace.php:0
    0.0064     365808     -> str_split($string = 'Xdebug') C:\Users\Test\trace.php:8
    0.0200     366376     -> ret_ord($c = 'X') C:\Users\Test\trace.php:10
    0.0202     366376       -> ord($character = 'X') C:\Users\Test\trace.php:5
    0.0204     366376     -> ret_ord($c = 'd') C:\Users\Test\trace.php:10
    0.0205     366376       -> ord($character = 'd') C:\Users\Test\trace.php:5
    0.0207     366376     -> ret_ord($c = 'e') C:\Users\Test\trace.php:10
    0.0208     366376       -> ord($character = 'e') C:\Users\Test\trace.php:5
    0.0209     366376     -> ret_ord($c = 'b') C:\Users\Test\trace.php:10
    0.0210     366376       -> ord($character = 'b') C:\Users\Test\trace.php:5
    0.0211     366376     -> ret_ord($c = 'u') C:\Users\Test\trace.php:10
    0.0211     366376       -> ord($character = 'u') C:\Users\Test\trace.php:5
    0.0211     366376     -> ret_ord($c = 'g') C:\Users\Test\trace.php:10
    0.0212     366376       -> ord($character = 'g') C:\Users\Test\trace.php:5
    0.0215     282592
TRACE END   [2021-09-18 11:28:18.901926]

関数トレースを開始する

関数トレースの開始タイミングは、デフォルトではトリガーに設定されているので、条件を満たしてあげる必要があります。 GETパラメーターからトリガーする場合は、URLのGETパラメーターに XDEBUG_TRIGGER を付けて、Webブラウザからアクセスするだけです。 GETパラメーターが1つ以上ある場合は、? ではなく & で繋げます。 ブラウザに Xdebug の拡張機能を入れている場合は、そちらを使って Cookie からトリガーした方が便利です。

例:GETパラメーターからトリガーする場合
https://example.com/hoge/hoge?XDEBUG_TRIGGER

ファイルの出力先を指定する

トレースファイルの出力先のディレクトリは xdebug.output_dir で指定できます。 デフォルトの場合は一時ディレクトリ("C:\Windows\Temp")になります。

出力ファイル名の形式は xdebug.trace_output_name で指定できます。 デフォルトの場合は trace.%c 形式になります。%c はCRC32のことです。 タイムスタンプ形式にするには %t を使用します。

ファイルの拡張子は必ず .xt になり、変更できません。

php.ini
[xdebug]
xdebug.mode=trace
xdebug.output_dir=C:\xampp\xdebug_output
xdebug.trace_output_name=trace.%t

プロファイリング(モード:profile)

この機能は、PHPアプリケーションのパフォーマンスを分析し、ボトルネックを見つけるためのものです。 例えば、速度が遅いけど、どこが遅いのかわからないといった場合ですね。

この機能を有効にした状態でHTTPリクエストを送信すると、プロファイリング用のデータが cachegrind.out という形式のファイルとして出力されます。

その出力された cachegrind.out ファイルを、KCacheGrind 互換のビュアー(Windows の場合は QCacheGrind)で読み込めばボトルネックを探せます。

qcachegrind.png

ファイルの出力先を指定する

cachegrind.out ファイルの出力先のディレクトリは xdebug.output_dir で指定できます。 デフォルトの場合は一時ディレクトリ("C:\Windows\Temp")になります。

出力ファイル名の形式は xdebug.profiler_output_name で指定できます。 デフォルトの場合は cachegrind.out.%p 形式になります。%p はプロセスIDのことです。 タイムスタンプ形式にするには %t を使用します。

php.ini
[xdebug]
xdebug.mode=profile
xdebug.output_dir=C:\xampp\xdebug_output
xdebug.profiler_output_name=cachegrind.out.%t

ガベージコレクション統計(モード:gcstats)

この機能は、PHPの内部ガベージコレクターがトリガーされるタイミング、クリーンアップできた変数の数、所要時間、実際に解放されたメモリの量を確認するためのものです。 PHPのガベージコレクション(GC)は、メモリとパフォーマンスに深刻な影響を与える可能性があるため、トリガーされるタイミングと各実行の効率を理解することで、プログラムを最適化できます。 ただし、このレベルの最適化をする必要はほとんどないとは思いますので、用途は限られるでしょう。

Garbage Collection Report
version: 1
creator: xdebug 3.0.4 (PHP 8.0.4RC1)

Collected | Efficiency% | Duration | Memory Before | Memory After | Reduction% | Function
----------+-------------+----------+---------------+--------------+------------+---------
     9965 |     99.65 % |  0.00 ms |      10293072 |      1125272 |    89.07 % | hoge
    10000 |    100.00 % |  0.00 ms |      10325272 |      1125272 |    89.10 % | hoge
       36 |      0.36 % |  0.00 ms |       1158168 |      1125048 |     2.86 % | gc_collect_cycles

ガベージコレクション統計を開始する

ガベージコレクション統計を開始するには、2つの方法があります。

コマンドオプションで指定する

1つ目の方法は、phpコマンドのオプションで指定する方法です。 主な使用例は、個々のCLIスクリプト実行の統計を収集することです。

php -dxdebug.mode=gcstats -dxdebug.start_with_request=yes your_script.php

関数を直接呼ぶ

2つ目の方法は、PHPスクリプトで xdebug_start_gcstats() を直接呼び出して開始することです。 停止させる場合は、xdebug_stop_gcstats() を呼び出します。 これにより、統計収集をいつ開始し、いつ停止するかをより細かく制御できます。

php.ini
[xdebug]
xdebug.mode=gcstats
PHPファイル
<?php
xdebug_start_gcstats();

// 調べたい処理

xdebug_stop_gcstats();

ファイルの出力先を指定する

統計ファイルの出力先のディレクトリは xdebug.output_dir で指定できます。 デフォルトの場合は一時ディレクトリ("C:\Windows\Temp")になります。

出力ファイル名の形式は xdebug.gc_stats_output_name で指定できます。 デフォルトの場合は gcstats.%p 形式になります。%p はプロセスIDのことです。 タイムスタンプ形式にするには %t を使用します。

php.ini
[xdebug]
xdebug.mode=gcstats
xdebug.output_dir=C:\xampp\xdebug_output
xdebug.gc_stats_output_name=gcstats.%t

コードカバレッジ解析(モード:coverage)

この機能は、PHPUnit でテストを実行したときに、テスト対象のコードのうちどれくらいの割合がテストされたかというのを調べるためのものです。 基本的には PHPUnit と組み合わせて使われるものです。 そのため、主に PHPUnit の機能の使い方の説明になってしまうので、詳しい使い方は「PHPUnit の使い方」を参考にしてください。 Xdebug でこの機能を有効にしておかないと、PHPUnit でコードカバレッジ解析はできません。

php.ini
[xdebug]
xdebug.mode=coverage

参考サイト

関連記事

プログラムを書いていると気になるのがコードの読みやすさです。複数人で開発している場合などは特にコードの読みやすさは重要です。PHP_CodeSniffer とは?PHP_CodeSniffer は、PHPのコードがちゃんとコーディング規約に沿って記述されているか検査したり、コーディング規約に違反している個所を自動的に修 ...
PHPのコードを実行する前に、バグがあるかどうか調べられると便利だとは思いませんか?PHPはスクリプト言語ですので、いくら文法的に正しいコードであっても、実際に実行させるまでバグか発生するかどうかわからないという、スクリプト言語であるが故の本質的な問題を抱えています。C や Java など他のコンパイル言語ではコンパイ ...
PHP_CodeSniffer や PHPStan などで、コードの文法的な正しさは確認できますが、そのコードが本当に正しい動作を行っているかどうかを確認するためには、やはり最終的には動作させてみるしかありません。PHPUnit とは?PHPUnit は、PHPのテストフレームワークです。その名前からわかる通り、基本的 ...

記事検索

最新記事

RSSフィード