PHPerのための「Xdebugの活用方法」を語るTechCafe

PHPer's NEWS!!

The New Life of PHP – The PHP Foundation
・もっとPHPの言語内でパラダイム・シフトが活発になりそう
・レガシーシステムを作っている会社はDOKIDOKI★HETOHETOが待っていそう★★

2021 アドベントカレンダー Laravel
著名なエンジニアによる記事が満載。Laravel の最新情報などもそろっている雰囲気です

JetBrainsがコードエディタの「Fleet」を発表
PHPは実装予定。単純に使ってみたいです。

Appleシリコン対応Docker Desktop、一般提供を開始
M1 Mac不具合が解決していけば最新Mac買いたい。
まだIntel Macの信用度は高い。

PHP: PHP 8.1.0 Release Announcement
新機能については、うちのTechBlogでもまとめられています

PHPerKaigi petit - PHP8.1リリース祝賀会
参加者のアイコンが見たことあるアイコンばかり…

「動的プロパティの禁止」が僅差で可決
ライブラリやら諸々取り込むのは大変そう
ちなみに投票数の2/3が賛成で可決です

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

Xdebug

Laravel Sail の Xdebug 設定方法

そもそもデバッグツールって何よ

  • de(除去) - bug(不具合) のためのツール
  • 多くのデバッグツールは基本機能として以下を備えている
    • ブレイクポイント
      • 実行中のプログラムを任意の箇所で一時停止する
    • ステップ実行
      • ソースコードを1ステップずつ実行する
      • プログラムの流れを追う際に使用
    • 変数の可視化・変更
      • 実行中のプログラムの変数の値を確認したり変更する
    • 関数・式の実行
      • デバッグ中に任意の関数や式を実行する
  • デバッグツールがないと調査がとても大変。すごく大変。
    • 大量のデバッグログ…
    • 処理を無理やり分岐させるための調査用の実装…
    • 同時実行など再現が難しい場合…
    • デバッグ用に入れた処理が本番に残ってしまって大災害…

Xdebug の概要

  • Xdebugは、PHPでデバッグを行う上で便利な機能を提供する拡張機能
  • 多機能で、基本的なデバッグツールとしての機能だけでなく、様々な機能を持つ

導入方法

  • ポイント
    • C言語で実装されており、コンパイルされたファイル.soファイルを組み込む(php.iniに読み込み設定を追記)ことで有効になる
  • 公式のインストール手順
    • Linux:公式リポジトリを使う
      • 手軽。
      • 一方、リポジトリに反映されているものを使うため、最新バージョンが使えない場合も。
      • 例:Ubuntu
        • sudo apt-get install php-xdebug
        • Ubuntu20.04だとv2系が入る
    • PECLで入れる
      • こちらも手軽。Macの場合はこちら。
      • pecl install xdebug
    • ソースをコンパイル
      • 特定のバージョンが必要な場合など、特別な制約がある場合はこちら。
      • 特に難しいわけではないが、公式の手順が何を意味しているのか理解しておいたほうがよいと思います。
  • Dockerで使う
    • 公式イメージの説明
    • Dockerfileの例
      ​​​​​​​​FROM php:8.1-cli
      
      ​​​​​​​​RUN pecl install xdebug \
      ​​​​​​​​    && docker-php-ext-enable xdebug
      
    • docker-php-ext-enableを記述すると、コンテナ上のPHPでxdebugが有効化される。

Step Debugging

ステップデバッグとは

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

デバッグ方法 (PhpStorm)

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

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

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

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

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

デバッグセッション再開

  • 次のブレークポイントへ進む
  • 次に通ったブレークポイントにて再度処理が止まる

ステップオーバ (F8)

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

ステップイン (F7)

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

ステップアウト (F8)

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

強制ステップイン

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

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

フレーム調査
  • どこから呼び出された処理かを確認
変数の調査 / 更新
  • 現在の変数に格納された値の確認
  • 値の編集も可能
式の評価
  • 選択した部分の式評価

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

その他テクニック

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

Improvements to PHP's error reporting

詳細

php.ini

​​​​```
​​​​xdebug.mode=develop
​​​​```

var_dump()の強化

  • サンプルコード
    ​​​​$sampleArray = [
    ​​​​    1, // int
    ​​​​    0.1, // float
    ​​​​    true, // bool
    ​​​​    "string", // string
    ​​​​    ["nest1", ["nest2", ["nest3"]]] // array
    ​​​​];
    
    ​​​​var_dump($sampleArray);
    
  • developモードがOFFのとき
  • developモードがONのとき
  • 補足情報
    • php.inihtml_errors設定が有効のときしかキレイにならないので注意
    • xdebug.var_display_max_depth
      • 配列やオブジェクトのネストについて、どの深さまで表示するか制御できる
    • xdebug.cli_color
      • コマンドラインで表示されるvar_dump()の結果に色を付けることができる

スタックトレースの追加

Tracing

概要

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

詳細

  • php.ini(設定例)
    ​​​​xdebug.mode=trace
    ​​​​xdebug.trace_format=0
    ​​​​xdebug.output_dir=/tmp/tracing
    ​​​​xdebug.start_with_request=no
    
  • サンプルコード
    ​​​​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というファイルが出力されました
  • 補足情報
    • xdebug.collect_assignments
      • 関数に渡された引数の値を出力できる
    • xdebug.collect_return
      • 関数の戻り値の値を出力できる
    • xdebug.trace_formatで出力フォーマットを選択できる
      • 1(コンピューター可読形式)
        • 実行結果
        • 公式が分析用のスクリプトを準備してくれている
      • 2(HTML)
        • 実行結果
    • その他にも設定が多数あり

Profiling

機能の概要

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

使い方

  1. php.ini 設定
    • ​​​​​​; profile の設定を有効化
      ​​​​​​xdebug.mode=profile
      ​​​​​​; profile の出力先
      ​​​​​​xdebug.output_dir=/tmp/profiling
      
  2. php のプログラム実行
    • xdebug.output_dir で指定したディレクトリにファイルが出力される
  3. Webgrind で確認
    • profiling されたファイルはそのままでも確認できるが、ツールを使うことで視覚的にわかりやすく確認できる
    • 他にもおすすめのツールがあれば教えてください
      • PhpStorm など?

使うシーン

  • パフォーマンスが悪い処理のボトルネック特定
  • 意図しない箇所で例外処理されてしまって原因特定が困難な時

備考

  • 現状の php.ini 設定の場合は、すべてのリクエストが profiling されてしまう
  • string xdebug.start_with_requesttrigger に設定することで profiling を開始したいタイミングを指定できる

備忘録

  • 項目名は Profiling なのに公式のURLはprofiler になっている

Code Coverage Analysis

機能の概要

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

使い方

  • 基本的には PHPUnit と組み合わせるのが一般的
  • php.ini の設定は不要
    • ソースコード上でカバレッジを取得したい箇所を xdebug_start_code_coverage()xdebug_stop_code_coverage() で挟むだけ
    • xdebug_get_code_coverage() を実行することで上記で挟んだ箇所のカバレッジを取得できる
    • サンプル
    • ​​​​​​  <?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: デッドコードになっている
    • 使うシーン
      • PHPUnit による単体テストがどの程度カバーできているかを確認する
      • デッドコードの洗い出しにも使えそう
        • 明示的なデッドコードは「-2」になっている箇所を見ればよいだけなのですぐに見つけられる
        • なかなか分岐に入りにくいようなケースの洗い出し
          • 本番環境やステージング環境などにカバレッジ取得の処理を組み込む
            • 開発環境などのソースが変更されやすい環境だと結果がおかしくなりそう
          • カバレッジの結果をマージ
            • これを定期的に実施
              • 長期間「-1」になっている箇所を確認
                • 使われなくなった関数などではいないか?
                • バージョンアップによって論理的にデッドコードになったのではないか?

  • 参加者の声
    • dockerてxdebugするときのコツ、落とし穴
    • デバックの実用的な実践例、使いどころやコツを広げて語ってほしい
    • Xdebugをprofilerモードで使う場合の使い方を教授いただけるとうれしいです
    • 優先度はかなり低めですが最近xdebugを使い始めてprofile, garbage 機能の使い方がまだdocを読んでいる途中でして分かってなく、もし議題が無ければ教授頂けるとすごく助かります!
    • gcstatsを活用してる方がいたらお聞きしたいです!

参考資料

Select a repo