PHP : ダンプなどのデバッグ情報をファイルに出力する

結論

この記事での課題解決の結論は、以下のワンライナーです。

error_log( print_r( $obj, true ), 3, __DIR__ . '/log.txt' );

PHPでの一般的なデバッグ

PHP を使って開発している方の多くは var_dumpなどを使ってデバッグされていることと思います。

私は以前、サーバーサイド Java でシステムを作っていたので、ステップ実行させてデバッグすることに慣れていましたし、それができる環境も整っていました。
IDE にデフォルトでビルトインサーバーがインストールされており、デバッガもすぐに設定できるからです。

しかし、PHPで開発を始めた際にサーバーサイド含めて xdebug の設定をするのが面倒で、ビルトインサーバーのパフォーマンスがひどく悪いためにvar_dumpでダンプ出力させてデバッグしてみたところ、「これもまぁ、やれないことはないな」と思いつづけて現在に至ります。

しかし、ちょっとうまくいかないこともあります。

簡単な解決方法があるケース

  1. ダンプする対象のオブジェクトや配列が長大な場合、非常に見にくい。
  2. ダンプ出力がWebサイト上の何らかのエレメントの後ろに隠れて見えない。

1番目は<pre>タグで囲って出力することで解決できます。
var_dumpの出力は本当はいい感じにタブや改行が入っているのですが、ブラウザでのHTML表示時にはそれらは全て無視されます。<pre>タグは改行は改行として、タブはタブとしてHTML上に出力されるため、整形された状態でダンプを見ることができます。

echo '<pre>';
var_dump( $obj );
echo '</pre>';

2番目はブラウザ上の、HTMLソースを見るという簡単な操作で解決することができます。
Chrome だと、右クリックなどでコンテキストメニューを表示し、「ページのソースを表示」することで、HTMLソースと共にダンプ出力を見ることが出来ます。

しかし、HTMLソースが長大な場合には、ダンプ出力がどこにあるのか探す必要はあります。

また、ソースとして出力されたダンプは整形されているので、1番目の問題の解決策にもなり得ます。

ブラウザ上では解決が難しいケース

  1. AJAX の処理なのでWeb画面上にはダンプ出力が表示されない。安易にダンプすると、レスポンスにダンプ出力が含まれてしまい、JavaScript がエラー終了する。
  2. サーバー側の処理完了後にリダイレクトされてしまい、ダンプ出力を見ることが出来ない。

このケースの1番目はブラウザのデベロッパーモードのネットワークタブなどで AJAX のリクエストを探し、レスポンスを見ることでダンプ自体は確認できます。
もちろん、サーバー側から正しくない JSON が返ってくるので、AJAX のレスポンスを処理するプログラムはエラーになります。
また、画面ロード時に実行される AJAX などはネットワークのログが大量に出力され、フィルターして探すなどする必要があって面倒でもあります。
しかし、冒頭の方法で全て解決できます。

2番目はWebブラウザ上ではお手上げです。サーバー上で実行されるリダイレクトの場合はvar_dumpのために出来ることは何もありません。
JavaScript でリダイレクトされる場合には、レスポンスが返ってきてJavaScript のリダイレクト処理が始まるまでの間にブラウザの停止ボタンを押すなどというアクションゲームにチャレンジすれば見ることができるかもしれません。
しかし、冒頭に書いた方法で解決できます。

ダンプ情報をファイル出力する

冒頭のコードを再度掲載します。

error_log( print_r( $obj, true ), 3, __DIR__ . '/log.txt' );

error_logというのは、第1引数の出力をシステムログや任意のログ、あるいはメールで送付させることもできます。

最初の引数には、print_r( $obj, true )とあります。

print_r

指定した変数に関する情報を解りやすく出力する

というものらしいですが、要するにvar_dumpと同じ内容を主力します。
しかしこの関数は実行した時点で出力してしまうため、var_dumpと同じになってしまいます。
出力せずにerror_logに渡すために、print_rの第二引数としてtrueをセットしています。

error_logの第2引数に数字の 3 を渡しています。
これは第3引数でセットされる、任意のファイルに出力するためのオプションです。

error_logの第3引数が出力先の指定です。
同一ディレクトリのlog.txtに出力するようにしています。

これで、必要なデバッグ情報は指定したログファイルに出力されるので、ブラウザ上の小細工など無しにダンプを見ることが出来ます。

AJAXのサーバーサイドのログも、ブラウザ上で小細工せず、JavaScriptのエラーも引き起こさず、リダイレクトされてダンプがどこかへ行ってしまうこともありません。

注意点

小さな注意点があります。

error_logは、ログ出力のための関数ですので、ファイルに追記されていきます。
これ自体は問題ありませんし、むしろありがたい場合もあります。
前のダンプと今のダンプを容易に比較可能だからです。
しかし注意しないといけないのは、

明示的に指定しない限り、message の 最後には改行文字は追加されません。

ということです。

連続してerror_logに出力する場合には、以下のようにした方が見やすいかもしれません。

error_log( print_r( $obj, true ) . "\n", 3, __DIR__ . '/log.txt' );