PHP

PHP開発者がいまさら聞けない、Xdebugの基礎の基礎

2017/05/30

Bruno Skvorc

76

Articles in this issue reproduced from SitePoint
Copyright © 2017, All rights reserved. SitePoint Pty Ltd. www.sitepoint.com. Translation copyright © 2017, KADOKAWA ASCII Research Laboratories, Inc. Japanese syndication rights arranged with SitePoint Pty Ltd, Collingwood, Victoria,Australia through Tuttle-Mori Agency, Inc., Tokyo

「Xdebug」は15年間愛されてきた、PHPの定番デバッグツール。それでもまだ使ったことがないPHP開発者のために基本的な使い方を紹介します。

Xdebugの登場から15年が経ちました。ここでXdebugの目的や機能をあらためて紹介します。

XdebugはPHPのエクステンション(コンパイルしてPHP環境にインストールするもの)で、デバッグの機能を提供します。

  • スタックの追跡。エラーが発生するまでの経過を詳細に表示する。関数に渡されたパラメーターも表示され、エラーの原因を探しやすくする
  • var_dumpを整形して出力する。VarDumper同様、色分けした情報と構造化ビューを生成。スーパーグローバルのダンパーが可能
  • コードのボトルネックを特定するプロファイラー。外部のツールでパフォーマンスのグラフをビジュアライズでき、Blackfireのようなグラフが書ける
  • 実行中のコードや、IDE、ブラウザーなどのエンドクライアントにリモートでXdebugを接続するリモートデバッガー。コードにブレークポイントを設定して1行ずつアプリケーションを実行できる
  • リクエスト中に実行されたコードの量を示すコードカバレッジ。ユニットテストで使う。テストでカバーしたコードの割合が分かる

Xdebugの使い方

Xdebugのインストール手順書は、ほぼすべてのケースを網羅しています。ですが、これから説明する機能を使うなら、エクステンションがインストールされてアクティベーション済みの改良版Homesteadがおすすめです。

高性能なIDEやBlackfireがあるのにXdebugが必要な理由

IDEには優れたコード・ルックアップ機能があるので、リンクフォーマットの機能が必要なのか疑問に思うでしょう。エラーや例外を扱うロガーも豊富にあり、Blackfireには関数トレースやプロファイラーもあります。しかし、Xdebugにはリンクフォーマット以上の機能があります。Blackfireはエクステンションのインストールやキーの設定が必要で、トレース履歴の保存は有料というハードルがあります。ロガーはあとからアプリケーションに組み込むのは簡単ではなく、早い段階で計画する必要があります。

さらに、Xdebugは適切なユニットテストの機能(テストのフレームワークがコードカバレッジレポートを作成するにはユニットテストが必要)や、リモートでブレークポイントを設定してデバッグする機能があります。また歴史が長いので安定していて、完成度の高いツールです。

既存のツールで満足していてXdebugの機能が必要ないなら不要ですが、効率的にプロジェクトを進めるために私にはXdebugが必須ツールです。

Xdebugを試してみよう

Xdebugのインストールが完了して使える状態であることを前提にします。準備ができていない人は改良版Homesteadをおすすめします。

シンプルなindex.phpファイルで新しいプロジェクトフォルダーを作成し、存在しない変数 $foo を出力します。

<?php

echo $foo;

出力結果:

Xdebug styled error

Xdebugを停止する

このスクリーンはよく見かけるので、Xdebugスタイルだと多くの人が気付いていません。そこでXdebugを停止して表示します。Xdebugを停止するには、改良版Homestead/etc/php/7.1/fpm/conf.d/20-xdebug.iniファイルを開いて、1行目をコメントアウトします。

;zend_extension=xdebug.so
xdebug.remote_enable = 1
xdebug.remote_connect_back = 1
xdebug.remote_port = 9000
xdebug.max_nesting_level = 512

We need to restart PHP-FPM afterwards:

PHP FPMを再起動します。

sudo service php7.1-fpm restart

注意:開発環境やPHPの環境によってXdebugのiniファイルの場所が変わります。各ドキュメントを参照してください。

Bare PHP error

コールスタックに関する情報が表示されず、役に立ちません。単一ファイルの単一コードなので差を実感しにくいですが、あとで複雑な状況での使用例を紹介します。

先ほどのファイルからコメントを除いてXdebugを有効にし、PHPを再起動して進みます。

ファイルをクリックで開く

IDEにこだわりがあるなら(私はPhpStormを使っています)、スタックトーレスでファイルをクリックして直接IDEで開けると、デバッグの速度が向上します。PhpStormでの実装を説明します。

先ほどと同様に20-xdebug.iniファイルを開き、次のコードを追加します。

xdebug.file_link_format = phpstorm://open?%f:%l

この機能は使えるブラウザーと使えないブラウザーがあります。Operaはphpstorm://を表示できないのでクラッシュします。Firefox、Chromeは動きます。

先ほどの無効なPHPページを再読み込みするとクリックができるリンクが表示され、エラーの場所でIDEが立ち上がります。

Xdebug allows clicking through to the IDE

ほかのIDEやエディターでも同様に動作します。

XdebugをVagrantやPhpStormで使う

少しブレイクです。PHPランタイムがメインマシンに影響ぜず速くスムーズに動くために、現在ではバーチャルマシン上で多くの開発が進められています。バーチャルマシン上でのXdebugの使い方がわかりますか? 複雑な環境でも、ブレークポイントを設定して1行ずつ実行しながらデバッグできるのでしょうか?

幸いにもXdebugにはブレークポイントを使ったリモート接続機能があります。詳しくは、Gifアニメの解説が分かりやすいセットアップマニュアルを参照ください。

プロファイラを使う

最後にプロファイラという見逃しやすい機能を紹介します。これにはLaravelのような重いアプリケーションが必要です。

composer create-project --prefer-dist laravel/laravel xdebug

再び20-xdebug.iniファイルを開いて、次のコードを追加します。

xdebug.profiler_enable_trigger = 1
xdebug.profiler_output_dir = /home/vagrant/Code/

プロファイラを常駐させる xdebug.profiler_enable = 1 は使いません。代わりにトリガークエリパラメーター「XDEBUG_PROFILE」で必要時に起動させます。cachegrindプロファイルをVMのメイン共有フォルダーに出力し、ホストのオペレーティングシステムのツールで調べられるようにします。

PHPを再起動しhomestead.app/?XDEBUG_PROFILEを実行して試してください(homestead.appを利用中のvhostかVMのIPに置き換えてくだしい)。ファイルが作成されます。

Cachegrind file in the main folder

OSにはcachegrindインスペクターツールがあります。OS XはHomebrew経由で簡単にインストールできるqcachegrindです。使用しているOSのビジュアライザ―に従ってインストールしてください。インストールできたら以下のコードを実行します。

 brew install qcachegrind --with-graphviz

ファイルをビューアーで開くと、実行フローがステップごとに表示されます。

Cachegrind explored

Blackfire同様、プロファイラで開発中のコードが実行されるプロセスについて、多くのデータと深い気づきを得られます。プロファイラーのローカル出力を見れば、パフォーマンスと実行の複雑さを自動的にトラッキングできます。

XdebugのRenderをLaravelで使用する

デフォルトでLaravelにはカスタムエラーレポートとレンダリングが設定されています。先ほど未定義の変数で起こしたようなエラーはLaravelでは次のように表示されます。

<?php

use Illuminate\Http\Request;

Route::get('/', function(Request $request){
    echo $foo;
    return view('welcome');
});

An error of an undefined variable in Laravel

SymfonyのLaravelが使用しているエラースクリーンはXdebugのクリックスルーが使えるように設定されています。試しに表示されたファイルや行をクリックしてください。メモリーの出力がないのは残念です(Xdebugはデフォルトでスタックトレースにすべてのタイミングのメモリーの使用量を出力します)。開発モードのままXdebugのスクリーンに戻して、メモリーの使用量を調べます。

<?php
use Illuminate\Http\Request;

Route::get('/', function(Request $request){
    ini_set('display_errors', 1);
    restore_error_handler();
    echo $foo;
    return view('welcome');
});

デフォルトのルートを更新して、はじめにエラーの表示を有効化します(先ほど示したスクリーンはエラー自体を表示しているのではなく、スタックトレースがキャッチした例外を手作業で抽出してレンダリングしたものです)。Laravelのエラーハンドラ―をオーバーライドして、デフォルト値に戻します。

再読み込みするとXdebugのスクリーンが表示され、スタックトレースの履歴と、メモリーの使用量が確認できます。

Laravel's Xdebug call stack

続きは実際に自分の手を動かして試してください。ドキュメントを読みオプションを使って、構築中のアプリケーションについて調べてみてください。

最後に

Xdebugはすべての開発者が活用できるツールです。文字通り強力なエクステンションで、日々利用している言語の幅が広がり、ユーザーフレンドリーになって、エラーの原因を特定しやすくなります。

誕生から15年、Xdebugはデバッグツールに求められる水準を高めてきました。Xdebugを開発してメンテナンスしてきたDerickに感謝します。Xdebugを実際に使ってみて、詳細な使い方や注意点、これまで誰も思いつかなかった秘密の活用方法など発信してください。一緒にXdebugを広めて、さらに15年使われるようにしましょう。

誕生日おめでとう、Xdebug!

(原文:Getting to Know and Love Xdebug

[翻訳:内藤 夏樹/編集:Livit

Copyright © 2017, Bruno Skvorc All Rights Reserved.

Bruno Skvorc

Bruno Skvorc

コンピューターサイエンスと英文学の修士号を持つクロアチア出身のプログラマーです。SitePointのPHPチャンネルのエディターで、Diffbot.comのデベロッパーエバンジェリストです。古いコードを黒死病のように遠ざけて、最先端のプロジェクトに関わるようにしています。ランニングマシン型の机を愛用し、(ボード)ゲームをしてときにはブログを書いています。

Loading...