RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

Xdebugの活用方法について語り合う【PHPTechCafeイベントレポート】

特集「Xdebugの活用方法」を語る

弊社で毎月開催し、PHPエンジニアの間で好評いただいているPHP TechCafe。
2022年2月のイベントではXdebugの活用方法」について語り合いました。

弊社のメンバーが事前にまとめてきたXdebugの基礎知識や使い方の説明資料にしたがって、他の参加者に意見を頂いて語り合いながらXdebugの活用方法を学びました。
今回はその内容についてレポートします!

rakus.connpass.com

デバッグツールについて

デバッグツールとはバグを除去するときに使用するツールです。
デバッグ(debug) は de(除去) - bug(不具合)という意味です。

多くのデバッグツールは以下の基本性能を備えています。

  • ブレイクポイント
    実行中のプログラムを任意の箇所で一時停止する
  • ステップ実行
    ソースコードを1ステップずつ実行する
  • 変数の可視化・変更
    実行中のプログラムの変数の値を確認したり変更する
  • 関数・式の実行
    デバッグ中に任意の関数や式を実行する
    デバッグツールがないとバグ修正が大変になるケースとして、以下が挙げられました。
    • 大量にデバッグログを仕込むことになる
    • 処理を通すことが難しい部分をデバッグする時
    • 同時実行など再現が難しい場合
    • デバッグ用に入れた処理が本番に残ってしまって大災害を引き起こす

その他、var_dumpなどで手軽にコードの動きを見たい場合はそちらを活用するなど、
「ツールとコードの両者を柔軟に使えると良い」という意見もありました。

Xdebugとは

PHPデバッグを行う上で便利な機能を提供する、拡張機能 です。
PHPにおいては、デバッグツールのデファクトツールになっているものです。

多機能で、基本的なデバッグツールとしての機能だけでなく、様々な機能を持っています。
デバッグの機能が使われることが多いですが、他にも様々な便利機能があり順に紹介されました。

導入方法

XdebugC言語で実装されており、コンパイルされたファイル.soファイルを組み込む(php.iniに読み込み設定を追記)ことで有効になります。
導入手順は公式のものを使用する方法と、Dockerを使用する方法の2つが紹介されました。

公式のインストール手順

  • Linux公式リポジトリ
    こちらの方法ではメリットとして最も手軽であることが挙げられましたが、デメリットとして最新バージョンが入らないこともあるようでした。
    Xdebugの最新バージョンはv3系ですが、Ubuntu20.04ではv2系が入ってしまうため、注意が必要です。
  • PECL(ピクル)
    PECL: PHP拡張機能やライブラリなどを追加するためのパッケージ管理ツール
    php.iniへの設定も自動で行ってくれるため、Macユーザーにとっては便利だという紹介がありました。
  • ソースをコンパイル
    こちらの方法が必要なケースとしては
    • 特定のバージョンが必要
    • ネットワーク、セキュリティの関係上パッケージ管理ツールが使用できない
      といったことが挙げられました。
      また、「手順が難しいわけではないが、コマンドを検索しソースからコンパイルされる場合に、実際に何が行われているかということを理解してから行う方がよいのではないか?」という意見もありました。
  • Dockerで使う
FROM php:8.1-cli

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

docker-php-ext-enableを記述すると、コンテナ上のPHPXdebugが有効化されます。
自身のプロジェクトの状況や環境に合わせて、様々な方法が選択できる点が非常に良いと思いました!
また、デバッグの際にデバッグツールを使用するかどうかのアンケートの結果、ツールを使用しない方が多数派だったようです。
その結果を受けて、Xdebugやdumpを利用することのメリット/デメリットが解説されました。

Xdebugのデメリットとしては動作が重い点が挙げられ、php.iniで設定を消すなどして軽量化を図ったという経験が語られていました。
dumpのデメリットとしては、消し忘れが事故につながる点が挙げられ、できるだけログに出力するようにしているという方法が語られました。

他にも

  • 新卒で入ったときに先輩から「ウェブブラウザの画面には出すな事故るから」って言われましたね。
  • 「何かAAAって出てきたんだけど」って。そんな報告聞きたくない!冷や汗すごいと思う。
  • 「var_dumpで事足りるじゃん」って宗教になってしまいました。「いやそれはないから目を覚ませ」って言った記憶があります。
    などの体験が語られていました。
    最後に
    • Xdebugを簡単に入れられない古いサービスとかだとやむなし
    • Xdebugが使える人はどんどん使っていくほうが良い
      という結論に至りました。

Xdebugの便利な機能

Step Debugging

Xdebugの機能について、PhpStormの画面を使って紹介されました。

ステップデバッグとは

任意の行で処理を止めながら行う、デバッグのことです。

デバッグ方法 (PhpStorm)

1. 受信デバッグ接続のリッスンを有効にする

2. ブレークポイントをセット

3. デバッグセッションの開始

対象のページをリロードすると、ブレークポイントで処理が止まります。

ステップデバッグでできること

デバッグセッション再開

ステップオーバ (F8)

  • 次の行へ処理を進める
  • 進める行のメソッドがある場合、メソッド内の処理はスキップされる
  • メソッド内にブレークポイントがある場合は、そこで止まる
    • "強制ステップオーバ" を使うことで、スキップもできる

ステップイン (F7)

  • メソッド内の処理を調べたい時に利用
  • 止まっている行にあるメソッド内の処理に入って先頭処理で止まる

ステップアウト (F8)

  • 調査中のメソッド内に問題がないことがわかった時に利用
  • 現在のメソッドから抜けだして、呼び出し元の処理で止まる

強制ステップイン

  • ステップインではサードパーティのライブラリなどのメソッドへ入ることができない
  • 強制ステップインでは、これらのメソッド内の処理へ入ることができる

このあたりの機能を見るだけでも、var_dumpでデバッグするよりも色々なことができることが分かります。
ここで紹介された機能について、

「基本的にはこのステップアウトぐらいまでは割とどういうIDEでもありますかね。」
「強制ステップインはPhpStormにユニークな機能として実装されていますね。」
「正直強制ステップインはあまり使わずに何とかなっていたので、意図して使い分けたりとかはしてなかったですね。」

といった経験が語られました。

停止している処理での調査

よくコードを追っていると行を見失うことがありますが、「停止している行を表示」するアイコンを押すと止まっている行に移動してくれます。
それらの機能について紹介されました。

フレーム調査

どこから呼び出された処理かを確認できます。

変数の調査 / 更新
  • 現在の変数に格納された値の確認
  • 値の編集も可能

式の評価
  • 選択した部分の式評価

  • アイコンから任意の式での評価結果確認も可能

こちらの機能についてはXdebugで止めながら、途中に適当な評価式を書いて変数の中身を見る必要がなく、直接確認できるというメリットが紹介されました。

その他テクニック

その他、いくつか紹介された機能を挙げておきます。

停止している行を表示
  • デバック時に停止している行を見失った時に使用
ウォッチリストに変数を追加
  • 変数を監視リストとして登録可能
ブレークポイントのミュートモード

その他の機能

続いて、その他便利機能が5つ紹介されました。
まずはエラーレポートを向上させてくれる機能の紹介です。
こちらは大きく分けてvar_dumpの強化、スタックトレース追加の2つがあります。

1. エラーレポート

詳細

まずは、php.iniのxdebug.modeをdevelopにする必要があります。

php.ini

xdebug.mode=develop

var_dump()の強化

var_dumpの出力を成形したり、装飾するためにHTMLエラーを有効にする必要があります。

html_errors=1

補足情報として、php.inihtml_errors設定が有効のときしかキレイにならないという注意点が挙げられました。

<?php

 $sampleArray = [
     1, // int
     0.1, // float
     true, // bool
     "string", // string
     ["nest1", ["nest2", ["nest3"]]] // array
 ];

 var_dump($sampleArray);

こちらの出力結果をブラウザ上で表示すると、以下の結果になります。

  • developモードがOFFのとき

  • developモードがONのとき

    この結果を受けて、developモードをONにしたときのメリットとして以下の点が挙げられました。

    • 改行などを成形、intが緑でFloatがオレンジといったように色がつき、見やすくすっきりする
    • ネストしている配列に、3つ目以降が省略されて表示される
      なお、ネストについてはxdebug.var_display_max_depthを設定することで表示する階層を制御できます。

その他、コマンドライン上でも色を付ける方法が紹介されました。
こちらはxdebug.cli_colorを設定することで表示される、var_dump()の結果に色を付けることができます。
参加者からも「var_dumpはプレタグで図った記憶がありますね」というコメントが挙がりました。

これをきっかけに

「このXdebugできれいになっているのも、HTMLのプレタグを付けてくれているっていうのがありますね。HTML化して共有してくれていると。」
Xdebug入れずにvar_dumpしたらページのソースを見ると改行されているのが分かるって感じになりますね。ブラウザ上だとbrとかあるけど……」
「それでプレタグで囲ったらってことですね。」
「printlnなんかも使えますね。その辺り使ってわかりやすくできます。」

という話題で盛り上がりました。

2.スタックトレースの追加

エラーが起こった際、developモードをONにすると綺麗に出力してくれます。

  • developモードがOFFのとき
  • developモードがONのとき

ここでは注意点として

Xdebugありでvar_dumpに吐き出すと、HTMLありで見にくくなる」
「var_dumpの結果をログに吐き出すときはdevelopモードをoffにしたほうが良い

ということも紹介されました。

3.トレーシング

トレースとは

関数がどういう経路で出力されているかを確認したり、関数の戻り値を確認することで、システムの全体像を把握することです。
Xdebugを使用することで関数呼び出しの履歴を出力できるため、以下のメリットが挙げられました。

  • 関数がどのような経路で呼ばれているか、全体像を把握できる
  • 引数、戻り値も確認できる

また、xdebug.mode=traceに設定するとトレーシングがオンになると紹介がありました。

  • php.ini(設定例)
xdebug.mode=trace
xdebug.trace_format=0
xdebug.output_dir=/tmp/tracing
xdebug.start_with_request=no

続いてサンプルコードを使用し、実際に出力を確認しました。

  • サンプルコード
<?php

class SampleClass {
    public function a() {
        $this->b();
    }

    private function b() {
        var_dump("tracing");
    }
}

$sampleClass = new SampleClass();

xdebug_start_trace();
$sampleClass->a();
xdebug_stop_trace();

$sampleClass->a();

実行結果

trace.1373756769.xtというファイルが出力されました。

Time列が実行時間、Mem列が使用しているメモリです。
Function列が呼び出している関数と場所を表しています。
また、矢印(->)でネストの深さも表しています。

この結果について参加者から

「traceの実行時間まで出るのすごいですね。」

というコメントがあり、それをきっかけに

ボトルネックを調べられるの便利ですよね。DBのI/OのアクセスとかならSQLいじるとかありますし。」
「遅そうなところにこういうのを仕込んで、PHPの処理は遅くないけど内部実行のDBアクセスに時間かかってるなあって原因の切り分けがしやすそうですね。」

というメリットが会話で挙げられました。 また、以下の補足情報も紹介されました。

  • xdebug.collect_assignments
    • 関数に渡された引数の値を出力できる
  • xdebug.collect_return
    • 関数の戻り値の値を出力できる
  • xdebug.trace_formatで出力フォーマットを選択できる
    • 1(コンピューター可読形式):実行結果

これについては、

「公式が分析用のスクリプトを準備してくれている」
GitHubの中に載っているんですがこのスクリプトに食わせて実行すると結構分析してくれます。自分で分析用のプログラムとか組んでアレンジすることも出来るかもしれません。」
「人間には読めない形で出るのかと思ってました。関数ごとの呼び出しされた回数とかが出てきましたね。」
「一回データとして取り込んでしまえばこっちのものですからね。」

といった便利な活用方法が紹介されていました。

  • 2(HTML):実行結果

    この結果については、「人にやさしい」という意見が出ていました。
    その他にも設定が多数あり、「結構いろいろできるんだな」というXdebugの多機能さに感心する声もありました。

4. プロファイリング

機能の概要

処理の監視や記録を行う機能です。
処理に時間がかかっている箇所や、リソース消費の激しい箇所を特定することができます。

使い方

こちらもiniファイルに設定が必要です。

  1. php.ini 設定
profile の設定を有効化
xdebug.mode=profile
profile の出力先
xdebug.output_dir=/tmp/profiling

これらを設定しPHP のプログラム実行すると、 xdebug.output_dir で指定したディレクトリにファイルが出力されます。
出力されたファイルは人間には分かりにくいので実行結果を可視化するツールが公式で紹介されており、Webgrind が個人的に使いやすいと紹介がありました。

この機能の活用シーンとしては

  • パフォーマンスが悪い処理のボトルネック特定
  • 意図しない箇所で例外処理されてしまって原因特定が困難な時
  • 「実行したけれどどこで落ちたかわからない」ときにこれを実行すれば「ここで止まったな」というのがプロファイリングの結果からわかる

といった紹介がありました。 また、参加者から

「PhpStormで開くと定義した場所にそのままコードジャンプ出来るので楽しいです」

というコメントがあり、これについて

  • 処理が重なっているところを押したら、該当のコードへジャンプ出来るということです。
  • 便利ですね!
  • さすがPhpStorm!

など、PhpStormへのポジティブな声が挙がりました。
他にも注意事項として、

  • 現状の php.ini 設定の場合は、すべてのリクエストが profiling されてしまう
  • 処理が重いスクリプトを気にせず実行しまくっていると、プロファイルの実行結果だけでディスク容量をかなり食ってしまうことになる
  • string xdebug.start_with_requesttrigger に設定することで profiling を開始したいタイミングを指定できるため、不用意に実行されないようにしたほうが良いと思う

といった点が挙げられました。

5.Code Coverage Analysis

機能の概要

処理を通過した箇所を記録することができます。
単体テストなどで、そのプログラムがどの程度テストできているかを把握できます。

使い方

  • 基本的には PHPUnit と組み合わせるのが一般的です。
  • php.ini の設定はおそらく不要です
    • ソースコード上でカバレッジを取得したい箇所を xdebug_start_code_coverage()xdebug_stop_code_coverage() で挟むだけ
    • xdebug_get_code_coverage() を実行することで上記で挟んだ箇所のカバレッジを取得できます。
      ここでは公式のサンプルコードを用いて話題が進みました。
      Xdebug 公式サイト
      functionAとBが存在し、Bに6と10を与えて結果をもらってくるPHPファイルがあるとします。
      ここにstart_code_coverageを入れてget_code_coverageを実行し、var_dumpに出力させると実行結果が出てきます。

<サンプル >

<?php

xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);

function a($a) {
    return;
    echo $a * 2.5;
}

function b($count) {
    if ($count > 25) {
        echo "too much\n";
    }
    for ($i = 0; $i < $count; $i++) {
        a($i + 0.17);
    }
}

b(6);
b(10);

var_dump(xdebug_get_code_coverage());

<実行結果>

array
    '/home/httpd/html/test/xdebug/docs/xdebug_get_code_coverage.php' =>
    array (size=11)
        5 => int 1
        6 => int -2
        7 => int -2
        10 => int 1
        11 => int -1
        13 => int 1
        14 => int 1
        16 => int 1
        18 => int 1
        19 => int 1
        21 => int 1

実行結果がキーバリューの形で出力されます。

  • キー
    • 対象ファイルの行数
  • 値 : カバレッジ取得結果
    • 1: 実行した
    • -1: 実行していない
    • -2: デッドコードになっている

まず 5 => int 1に着目します。
サンプルコードの5行目 return; はreturnが実行できたので「1」となっています。

6 => int -2 は直前の5行目でreturnしており、その後の処理が絶対に実行されないので「-2」となっています。

11行目if ($count > 25) は$countが25以上の時に実行されるコードですが、
サンプルコードは6,10しか渡しておらず条件を満たさないため実行されません。
そのため「-1」となっています。

カバレッジ

以前ラクスエンジニアブログにて、テストコードの書き方をご紹介致しました。
tech-blog.rakus.co.jp

その際に使用したコードのカバレッジを見てみましょう。

DiceClassに対して作られたテストコードがどの程度カバーできているかを表しています。
結果は全て100%となっています。
テストケースとしての精度が高く、カバレッジとしては問題無いですね。

このように、オールグリーン(100%)になっているかどうかをCode Coverageで確認することができます。
これによるメリットとして、

  • 単体テストのテストコードがどの程度書けているかを確認できるのはもちろん、「デッドコード」になっている箇所を早期に見つけることができる
  • 中々分岐に入らないケースですね。実際にリリースすると「全然入っていない分岐があるけど、論理的にデッドコードじゃない?」みたいなものがわからなかったりします。
    そういったところも比較的実行し続ければある程度判断できるんじゃないかなと思います。
    現実的じゃないですが本番環境やそれ相当のステージ環境にカバレッジ処理を組み込んでぐるぐる回すことで「ずっと入っていない」ものを判断できると思います。
  • カバレッジで一番知りたいのはPHPUnitがちゃんと通っているかですよね。網羅しているかどうかが一番重要になるパターンだと思うので。
  • Xdebugが提供しているっていうのが面白いですね。燃える話です

など、Xdebugの機能の豊富さに改めて関心する声が多数挙がりました。

編集後記

以上、Xdebugの概要と大まかな機能について取り上げました。
ラクスでも今まで取り上げることが無かった話題でしたので、主催者/参加者ともに盛り上がりを見せていました!
今後もXdebugの活用方法や、新ニュースに着目していきたいと思います!

PHP TechCafe」では今後もPHPに関する様々なテーマのイベントを企画していきます。
皆さまのご参加をお待ちしております。
connpass.com


◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.