2010年1月16日土曜日

便利で最高のデバッグ関数を目指して

新しいバージョンの debug 関数を こっちのブログ で公開しています。
この記事の debug 関数は古いのでおすすめはしません。

PHPで開発時にデバッグするとき、
var_dump で十分な気もしますが
ちょっと足りないときもあります。

Posql 開発時によく使っているデバッグ関数を公開します。
Posql のソース中に debug($args); なんて記述が残ってたりします。

debug
<?php
/**
 * It aims at the most best debugging function
 *
 * @param   mixed   the value of target
 * @param   string  optionally, the subtitle into the LEGEND tags
 * @return  mixed   the value of the first argument as it is returned
 * @version 1.09
 * @access  public
 * @static
 */
function debug($value, $title = ''){
 static $defaults = array(
   'args'     => array(),
   'class'    => '',
   'file'     => '',
   'function' => '',
   'line'     => 0,
   'type'     => '',
   'object'   => null
 );
 $trace = function_exists('debug_backtrace') ? @debug_backtrace() : $defaults;
 $shift = ((array)array_shift($trace)) + $defaults;
 $trace = ((array)array_shift($trace)) + $defaults;
 $caller = '';
 if ($trace['type'] && $trace['class'] && $trace['function']) {
   $caller = $trace['class'] . $trace['type'] . $trace['function'];
 } else if ($trace['function']) {
   $caller = $trace['function'];
 }
 $trace = (is_array($trace) ? $trace : $shift) + $defaults;
 
 if (is_scalar($title)) {
   if (function_exists('wiki_encode')) {
     $title = wiki_encode($title);
   } else {
     $title = htmlspecialchars($title);
   }
 } else {
   $title = htmlspecialchars(var_export($title, true));
 }
 
 $file = $shift['file'];
 $line = $shift['line'];
 
 if ($file && $line && ($fp = @fopen($file, 'rb'))) {
   $buffer = '';
   $found  = false;
   $multi  = false;
   $retry  = false;
   $i = $line;
   while (!feof($fp)) {
     $found = false;
     $gets = fgets($fp);
     if (!--$i) {
       $buffer = $gets;
       if (preg_match('{debug\s*(\(.+\))[^;]*;}is', $gets, $match)) {
         $buffer = $match[1];
         $found = true;
         break;
       } else if (!$retry) {
         $retry = true;
         rewind($fp);
         $i = $line - 10;
         if ($i < 1) {
           $i = 1;
         }
         $buffer = '';
         continue;
       }
     } else if ($i < 0) {
       $buffer .= $gets;
       $pos = strpos(strtolower($buffer), 'debug');
       if ($pos !== false) {
         $buffer = substr($buffer, $pos);
       }
       if ($pos !== false 
        && preg_match('{\(((?>[^()]+)|(?R))*\)(?=[^;]*;)}', $buffer, $match)) {
         $buffer = trim($match[0]);
         $buffer = preg_replace('<^[()]>', '', $buffer);
         $found = true;
         $multi = true;
         break;
       }
       if (strlen($buffer) > 0x10000) {
         break;
       }
     }
   }
   fclose($fp);
   if (!$found) {
     $title .= sprintf(' <strong>Not found the point of called!</strong>');
   } else {
     if ($multi 
      && preg_match('{^[^()]*?\(((?>[^()]+)|(?R))*\)}', $buffer, $match)) {
       $replace = strtr($match[0],
         array(
           '(' => "\x01",
           ')' => "\x02",
           ',' => "\x03"
         )
       );
       $buffer = str_replace($match[0], $replace, $buffer);
     } else {
       $multi = false;
     }
     $buffer = preg_replace('{^\(|(?:,(?=[()])(?!\s*[$]\w).+|\))$|}s', 
                            '', $buffer);
     if ($title) {
       $buffer = preg_replace('{,\s*([\'"])?(?(1).*?\1|(?!\s*[$]\w).*)$}ms', 
                              '', $buffer);
     }
     if ($multi) {
       $buffer = strtr($buffer,
         array(
           "\x01" => '(',
           "\x02" => ')',
           "\x03" => ','
         )
       );
     }
     $title = sprintf('%s <em>(%s)</em>',
                      $title, htmlspecialchars($buffer));
   }
   unset($gets, $buffer);
 } else {
   $var = array_search($value, $GLOBALS);
   if ($value && $var) {
     $var = '$' . $var;
   }
   if ($var) {
     $title = sprintf('%s <em>(%s)</em>', $title, $var);
   }
 }
 
 ob_start();
 var_dump($value);
 $dump = str_replace('&apos;', '&#x27;', ob_get_contents());
 ob_end_clean();
 $node = extension_loaded('xdebug') ? 'div' : 'pre';
 printf(implode("\n",
     array(
       '<fieldset style="border:2px solid;padding-left:5px">',
         '<legend style="font:x-small verdana;">',
           '%s<small>@%s[%s#%u]</small>',
         '</legend>',
         '<%s>%s</%s>',
       '</fieldset>'
     )
   ),
   $title,
   htmlspecialchars($caller),
   htmlspecialchars(strtr($file, '\\', '/')),
   $line,
   $node,
   $dump,
   $node
 );
 flush();
 return $value;
}
?>

内部で wiki_encode という関数があれば使う仕様になっています。

wiki_encode
<?php
/**
 * Replace simple wiki syntax with html
 *
 * @example  '**hoge**'
 * @results  '<em>hoge</em>'
 *
 * @example  '***hoge***'
 * @results  '<strong>hoge</strong>'
 *
 * @example  '*****hoge*****'
 * @results  '<strong><em>hoge</em></strong>'
 *
 * @example  '--hoge--'
 * @results  '<del>hoge</del>'
 *
 * @example  '___hoge___'
 * @results  '<u>hoge</u>'
 *
 * @example  'color=red:hoge;'
 * @results  '<span style="color:red;">hoge</span>'
 *
 * @example  'size=26px:hoge;'
 * @results  '<span style="font-size:26px;">hoge</span>'
 *
 * @example  'color=#ff9900:**hoge**;'
 * @results  '<span style="color:#ff9900;"><em>hoge</em></span>'
 *
 * @param  string  wiki syntax string
 * @return string  replaced html string
 */
function wiki_encode($string){
 $string = htmlspecialchars($string);
 $patterns = array(
   '<([*]{5,})(.+?)\1>su'
     => 
   '<strong><em>$2</em></strong>',
   '<([*]{3,4})(.+?)\1>su'
     => 
   '<strong>$2</strong>',
   '<([*]{2})(.+?)\1>su'
     => 
   '<em>$2</em>',
   '<(_{3,})(.+?)\1>su'
     => 
   '<u>$2</u>',
   '<([=-]{2,})(.+?)\1>su'
     => 
   '<del>$2</del>',
   '<([%/]{2,})(.+?)\1>su'
     => 
   '<em>$2</em>',
   '<color[:=]([#]?\w+)[:=](.+?)(?:;|$)>imsu'
     =>
   '<span style="color:$1;">$2</span>',
   '<size[:=](\d+)\w*?[:=](.+?)(?:;|$)>imsu' 
     =>
   '<span style="font-size:$1px;">$2</span>'
 );
 foreach ($patterns as $pattern => $replace) {
   $string = preg_replace($pattern, $replace, $string);
 }
 return $string;
}
?>

例として適当なスクリプトを作ってみます。


hoge.php
<?php
require_once 'debug.php'; // debug関数が定義してあるファイル

class Hoge {

    var $name;

    function Hoge(){
        $this->name = 'Hoge';
        debug($this,'*****Hoge*****');
    }

    function getName(){
        return $this->name;
    }
}

function test(){
  $hoge = new Hoge();
  debug($hoge->getName());
}

test();

?>


実行結果は以下のようになります。
Hoge ($this)@Hoge->Hoge[C:/xampp/htdocs/hoge.php#10]
object(Hoge)[1] 
public 'name' =>string 'Hoge' (length=4)
($hoge->getName())@test[C:/xampp/htdocs/hoge.php#20]
string 'Hoge' (length=4)

実行された行番号、引数、ファイル名などがわかるようになります。
拡張モジュール "xdebug" が有効になっていると見栄えがさらによくなります。

ご自由にお使いください。


もっと便利な関数や拡張があればおしえてくだしあ


Syntax Highlighter 入れたよ。いい感じ

0 コメント:

コメントを投稿