EC studio EC studio 技術ブログ

2007年07月26日投稿者:山本 正喜

PHPのデバッグに便利な関数 – 応用編

前回のデバッグ基本編に続きまして、今回は応用編です。

debuglib

変数表示はprint_rvar_dumpなどを使用することが多いと思いますが、
<pre>などで囲ったとしてもとても見やすいとは言えません、、。
そこで、debuglib.phpを使用すればとても見やすく表示してくれます。

※debuglibはこちらのページから入手できます

print_rと同様に、文字列・配列・オブジェクトなどなんでも表示できます。
使い方は簡単で、

  1. require("debuglib.php");
  2.  
  3. $profile = array(
  4.     "company" => "EC studio",
  5.     "name" => "山本正喜",
  6.     "birth_month" => 12,
  7.     "birth_day" => 16,
  8.     "hobby" => array("dance","programming","travel")
  9. );
  10.  
  11. print_a($profile);

↓この場合表示はこうなります

debuglibの表示

この様に、debuglib.phpを読み込み、
print_rのかわりにprint_aを使えばOKです。
これは非常に便利なので、使わない手はないです。

ただ、配列やオブジェクトはうまく表示できるのですが、
単体の数値や文字列、null/true/falseは
正しく表示できないのが不便です。

(例)

  1. $str = "EC studio";
  2. print_a($str);

↓この場合表示はこうなります

print_a($str)の表示

また、ライブラリとして読み込む必要があるので、
本番の時にはなるべくシステムを軽くするために、
デバッグの時のみファイルを読み込むようにしたいところです。

そこで、EC studioでは下記の様な関数を
一枚かぶせて使用しています。

  1. /**
  2. * デバッグプリント
  3. *
  4. * <pre>
  5. * 変数や配列、オブジェクトなどをビジュアルに表示する。
  6. * print_rの変わりに使うと便利。
  7. *
  8. * debuglibの、print_a ラッパー。(debuglib.phpを動的にロードする。)
  9. * print_aが出力しないnullや、string、空配列などにも対応している。
  10. * </pre>
  11. *
  12. * @param mixed $val 変数
  13. * @param int $mode 0 = 表示 1 = 出力を返す
  14. * @param bool $show_object_vars オブジェクトを展開して表示する
  15. * @param int $limit 最大表示数 (FALSEで無制限)
  16. * @return string $mode = 1の時 出力結果。
  17. */
  18. function dprint_r($val,$mode=0,$show_object_vars=FALSE,$limit=FALSE){
  19.     //debuglib読み込み (print_a関数)
  20.     require_once("debuglib.php");
  21.  
  22.     if ($val === null){
  23.         if ($mode){
  24.             return "<span style=\"color:red;\">NULL</span>";
  25.         }else{
  26.             echo "<span style=\"color:red;\">NULL</span>";
  27.         }
  28.         return;
  29.     }
  30.     if ($val === false){
  31.         if ($mode){
  32.             return "<span style=\"color:red;\">FALSE</span>";
  33.         }else{
  34.             echo "<span style=\"color:red;\">FALSE</span>";
  35.         }
  36.         return;
  37.     }
  38.     if ($val === true){
  39.         if ($mode){
  40.             return "<span style=\"color:red;\">TRUE</span>";
  41.         }else{
  42.             echo "<span style=\"color:red;\">TRUE</span>";
  43.         }
  44.         return;
  45.     }
  46.     if (is_string($val)){
  47.         if ($mode){
  48.             return "<span style=\"color:#00008B;\">".htmlescape($val)."</span>";
  49.         }else{
  50.             echo "<span style=\"color:#00008B;\">".htmlescape($val)."</span>";
  51.         }
  52.         return;
  53.     }
  54.     if (is_numeric($val)){
  55.         if ($mode){
  56.             return "<span style=\"color:green\">".$val."</span>";
  57.         }else{
  58.             echo "<span style=\"color:green\">".$val."</span>";
  59.         }
  60.         return;
  61.     }
  62.     if (is_array($val) and !count($val)){
  63.         if ($mode){
  64.             return "<span style=\"color:green\">array()</span>";
  65.         }else{
  66.             echo "<span style=\"color:green\">array()</span>";
  67.         }
  68.         return;
  69.     }
  70.  
  71.     return print_a($val,$mode,$show_object_vars,$limit);
  72. }

print_aのかわりに、このdprint_rを使用しています。
これで使い勝手がぐっとよくなりました。
(print_rの代替として使えるようになりました)

非常に便利なこのdebuglibなのですが、注意が必要な点として、

・配列や要素になっているオブジェクトはデフォルトでは表示されない。
(第3引数にtrueを与えると表示されます)
循環参照を持つ変数では無限ループが発生する

ということに気をつける必要があります。

循環参照とは、

  1. $arr = array();
  2. $arr[0] =& $arr;

この様に、配列やオブジェクトなどで要素に自分自身への参照を持つものの事です。
こういった変数を表示させようとすると、debuglibでは無限に変数を展開し続けます。
(環境によってはApacheが停止します)

あまり循環参照を持つ変数を使用することは少ないですが、
お互いを参照し合うオブジェクトなどでも循環参照が発生するので、
注意が必要です。

※PHP組み込みのprint_rvar_dumpでは循環参照は
**RECURSION**という表示に置き換わりちゃんと表示できます。

dBug

こちらもdebuglibと同様に、変数を表示するライブラリです。
ColdFusionのデバッグ表示機能であるcfdumpタグの機能を
PHPで実現することを目的としたライブラリです。

※dBugはこちらから入手できます

debuglibと同様に

  1. require("dBug.php");
  2.  
  3. $profile = array(
  4.     "company" => "EC studio",
  5.     "name" => "山本正喜",
  6.     "birth_month" => 12,
  7.     "birth_day" => 16,
  8.     "hobby" => array("dance","programming","travel")
  9. );
  10.  
  11. new dBug($profile);

この様に使用します。
オブジェクトを new するとデバッグ表示できます。

↓今回の例だと、この様に表示されます

dBugの表示

他にもデータベースのリソースや、XMLのデータなども
表示することができます。

こちらのサンプルページを見るdBugでどういった事が
できるかがよくわかると思います。

基本的にはdebuglibと同様の機能ですが、
配列やオブジェクトなどをクリックすると折りたたむ事が
できるなど、より機能的になっています。

また、debuglibではできなかった循環参照の
変数表示もできるようになっています。
(2007/01/15 に実装された様なので、古いバージョンを
使用されている方はアップデートをおすすめします)

ただ、dBug.phpを読み込んだ時点
javascriptやcssのコードが出力されてしまうので、
システムに組み込むには使いづらいかもしれません。

EC studioではシンプルで見やすいdebuglibの方を採用しています。

あると便利な小さい自作関数

ここではPHPの組み込み関数をちょっとした工夫で使いやすくした関数を
ソースコード付きでご紹介します。

■cprint_r

print_rの表示結果をHTMLタグに埋めこんで表示します。
画面には表示させたくないデバッグ変数の表示や、
本番環境などで緊急にテストしたい時に、、、(汗)

  1. /**
  2. * コメントで変数を出力する
  3. *
  4. * 本番などでデバッグ表示したい時などに
  5. * ソースをDEBUGで検索すれば見つけやすい
  6. *
  7. * @param mixed $val 変数
  8. */
  9. function cprint_r($val){
  10.     echo "<!-- [DEBUG START] ".print_r($val,1)." [DEBUG END]-->";
  11. }

■die_r

dieのprint_r版です。
dieで配列などを表示させたい時に。
(print_rはdebuglibやdBugに置き換えると便利です。)

  1. /**
  2. * print_r後にexitする
  3. *
  4. * print_rのdie版
  5. *
  6. * @param mixed $expression 変数
  7. * @param int $return false = 表示 true = 出力
  8. * @param string $expression = trueの時 出力結果。
  9. */
  10. function die_r($expression ,$return=false){
  11.     print_r($expression,$return);
  12.     exit;
  13. }

■count_hook

特定の回数コールされるとtrueを返します。
ループ回数が多いコードのデバッグ時に
仕込んでおくと非常に便利です。

  1. /**
  2. * 指定回数でtrueする。
  3. *
  4. * <code>
  5. * //30回でbreak
  6. * for ($i = 0;$i <100;$i++){
  7. *   if (count_hook(30)) break;
  8. * }
  9. * </code>
  10. *
  11. * ループなどのテストに便利。
  12. *
  13. * @param int $count 回数
  14. * @return bool 回数分コールされた時にtrue
  15. */
  16. function count_hook($count){
  17.     static $cnt = 0;
  18.  
  19.     $cnt++;
  20.  
  21.     if ($cnt == $count){
  22.         $cnt = 0;
  23.         return true;
  24.     }
  25.  
  26.     return false;
  27. }

(例)ループの10回目で抜ける

  1. for ($i = 0;$i <1000;$i++){
  2.     //何か重たい処理
  3.  
  4.     if (count_hook(10)){ //10回目でtrueになる
  5.         break;
  6.     }
  7. }

breakと組み合わせればループを抜けることもできます。
(dieで変数を表示して終了することも)

■count_die

count_hookのdie版です。
指定回数実行した時にdieを実行します。
(count_hookが必要)

  1. /**
  2. * 指定回数でdieする。
  3. *
  4. * <code>
  5. * //30回でdie
  6. * for ($i = 0;$i <100;$i++){
  7. *   count_die(30,"30回目");
  8. * }
  9. * </code>
  10. * ループなどのテストに便利。
  11. *
  12. * @param int $count 回数
  13. * @param string $message 表示させたい文字列
  14. * @return void
  15. */
  16. function count_die($count,$message=""){
  17.     if (count_hook($count)){
  18.         die($message);
  19.     }
  20. }

(例)ループの10回目でdie

  1. for ($i = 0;$i <1000;$i++){
  2.     //何か重たい処理
  3.  
  4.     //10回目でdie
  5.     count_die($something);
  6. }

count_hookに比べてシンプルに書けます。 ;-)

------------------------------------------

以上、デバッグ応用編でした。
PHPは便利な組み込み関数が多いので頼ってしまいがちですが、
同様の機能を持つ外部のライブラリを使用したり、
組み込み関数を組み合わせて少しカスタマイズした関数を
自分用に作ることで、使い勝手がぐっと良くなります。

それでは快適なデバッグライフを!


関連した記事:

この記事へのコメント

大変参考になりました。ありがとうございます。

debuglibは現在は上記の問題はfixされているみたいです。

投稿者: DU39 | 2011/01/30 日曜日 7:59:30
投稿者
人気のエントリー
カテゴリー
最近のエントリー
アーカイブ
Copyright© ChatWork, All Rights Reserved. secured by ESET.