PHP5でオブジェクトダンプ可能なデバッガ
20070721--Toytools_Debug_Core.phpにバグがあったのでソースを修正しました
デバッギングトレースはバックトレースなど色々方法はあるけど、僕がやっている方法を少し紹介
ページの最後にこんな形でダンプのトレースが表示できます(PHP5以上)
基本的な機能としては
などなど。
使い方
※本体のソースは下のほうにあります
<?php require_once 'Toytools/Debug.php'; //ロガーを作る $envLog = new Toytools_Debug( 'ENV' ); //ダンプ。第二引数はオプション【POST @ENV】のような名前になります $envLog->debug( $_POST ,'POST' ); //ダンプ。この場合は【ENV】のような名前になります $envLog->debug( $_POST ); ?>
デバッグレベルの変更
<?php Toytools_Debug::setDebugLebelByName( 'INFO' );//文字列から Toytools_Debug::setDebugLebel( Toytools_Debug::LEVEL_DEBUG );//定数から ?>
デフォルトはDEBUGレベルです。
DEBUG > INFO > WARN > ERROR > FATAL > NONE
こんな方法も使えます
<?php require_once 'Toytools/Debug.php'; class Test{ /** * @var Toytools_Debug */ private $_log; function __construct(){ $this->_log = new Toytools_Debug(__CLASS__); $this->_log->debug( 'テスト' , __FUNCTION__ ); } function hoge(){ $this->_log->debug( 'テスト' , __FUNCTION__ ); } } ?>
__CLASS__や__FUNCTION__といった定数を利用してあげることでデバッグに必要な情報を付与します
__FILE__、__LINE__なども必要に応じて出力してあげると便利です
ソース
Toytools/Debug.php
<?php require_once 'Toytools/Debug/Core.php'; /** * Debug Logger * @author kaw * @package Toytools * @usage * $debugger = new Toytools_Debug_Debug( 'TEST' ); * $debugger->debug( $mixedValue ); */ class Toytools_Debug{ const LEVEL_DEBUG = 4;// アプリケーションのデバッグでもっとも役立つ細粒度の情報イベントを指します。 const LEVEL_INFO = 3;// 粗粒度レベルでアプリケーションの推移を強調する情報のメッセージを指します。 const LEVEL_WARN = 2;// 潜在的に、有害な状況を指します。 const LEVEL_ERROR = 1;// まだアプリケーションが起動しつづけられるようなエラーイベントを指します。 const LEVEL_FATAL = 0;// おそらくアプリケーションの停止を起こすようなまさにサーバのエラーイベントを指します。 const LEVEL_NONE = -1;// ログに何も記録しません。 var $debugName; static $level = self::LEVEL_DEBUG; /** * CONSTRUCT * @param ロガー名 */ function __construct( $debugName = null ){ Toytools_Debug_Core::initialize(); $this->debugName = $debugName; } /** * ロガー名を取得する * @return string ロガー名 */ public function getDebugName($name = null){ if( !is_null($name) ){ return $name.' @'.$this->debugName; } return $this->debugName; } /** * デバッグレベルを設定する * @access public static * @usage * Toytools_Debug::setDebugLebel( Toytools_Debug::LEVEL_DEBUG ); */ public static function setDebugLebel( $debugLevel ){ if( !is_int($debugLevel) ){ throw new Error('Toytools_Debug::setDebugLebel argument need to Integer'); } self::$level = $debugLevel; } public static function setDebugLebelByName( $debugLevelName ){ $debugLevelName = strtoupper($debugLevelName); switch( $debugLevelName ){ case 'DEBUG': $debugLevel = self::LEVEL_DEBUG; break; case 'INFO': $debugLevel = self::LEVEL_INFO; break; case 'WARN': $debugLevel = self::LEVEL_WARN; break; case 'ERROR': $debugLevel = self::LEVEL_ERROR; break; case 'FATAL': $debugLevel = self::LEVEL_FATAL; break; case 'NONE': $debugLevel = self::LEVEL_NONE; break; default: throw new Error('Toytools_Debug::setDebugLebelByName undefined debug lebel name'); break; } self::setDebugLebel($debugLevel); } //--------------------------------------------------------------------- /** * とりあえずトレース(デバッグレベル扱いになります) * @param トレースする値 * @param デバッグ名 */ public static function trace( $value , $debugName = null ){ if( self::$level >= self::LEVEL_DEBUG ){ Toytools_Debug_Core::dump( $value , $debugName ); } } //------ レベル別 --------------------------------------------------------------- /** * DEBUGレベルトレース * @param mixed */ public function debug( $value , $name = null ){ if( self::$level >= self::LEVEL_DEBUG ){ Toytools_Debug_Core::dump( $value , $this->getDebugName($name) , self::LEVEL_DEBUG ); } } /** * INFOレベルトレース * @param mixed */ public function info( $value , $name = null ){ if( self::$level >= self::LEVEL_INFO ){ Toytools_Debug_Core::dump( $value , $this->getDebugName($name) , self::LEVEL_INFO ); } } /** * WARNレベルトレース * @param mixed */ public function warn( $value , $name = null ){ if( self::$level >= self::LEVEL_WARN ){ Toytools_Debug_Core::dump( $value , $this->getDebugName($name) , self::LEVEL_WARN ); } } /** * ERRORレベルトレース * @param mixed */ public function error( $value , $name = null ){ if( self::$level >= self::LEVEL_ERROR ){ Toytools_Debug_Core::dump( $value , $this->getDebugName($name) , self::LEVEL_ERROR ); } } /** * FATALレベルトレース * @param mixed */ public function fatal( $value , $name = null ){ if( self::$level >= self::LEVEL_FATAL ){ Toytools_Debug_Core::dump( $value , $this->getDebugName($name) , self::LEVEL_FATAL ); } } } ?>
Toytools/Debug/Core.php
<?php require_once 'Toytools/Debug.php'; /** * デバッグトレースのコア * abstractクラスにさせてそのうち継承させる?? */ class Toytools_Debug_Core{ private static $_cssEchoed = false; private static $_initialized = false; private static $_responseStack = ''; private static $_responseTraceEnabled = true; /** * 初期化をします * このメソッドをコールすることによってページ終了時にスタックに溜まっている情報を最後に自動的に出力します * シングルトンにしてデストラクタ使うのもありかも */ public static function initialize(){ if( self::$_initialized ){ return; } register_shutdown_function(array('Toytools_Debug_Core', "_flushStack"));//REGIST STATIC METHOD self::$_initialized = true; } /** * Stackに溜まっているものを出力します * @return void */ public static function _flushStack(){ if( !self::$_responseTraceEnabled ){ return; } self::_echoDebugCss();//CSSが未出力だったら出力 if( self::$_responseStack == '' ){ return; } echo '<br style="clear:both;margin-top:50px;" /><hr />'; echo self::$_responseStack; self::$_responseStack = ''; } public static function setNonTrace(){ self::$_responseTraceEnabled = false; } /** * 値をスタックに追加します * インターフェイスとしてDebugクラスから必要なものはこれだけ * 拡張するときにはこれだけ定義したInterfaceかAbstractクラスつくるかな * @param mixed $mixedValue * @param string|int|null ロガー名 * @param int デバッグレベル * @param Divをトレースするか(基本的には指定しないでください) */ public static function dump( $mixedValue , $loggerName = null , $debugLevel = null , $isEchoDiv = true , $traceObjectMethods = true ){ //self::_echoDebugCss();//CSSが未出力だったら出力 if( $isEchoDiv ){ self::_pushResponseStack( '<div class="toydebug">' ); } if( !is_null($debugLevel) ){ $level = self::_getDebugLevelLabel( $debugLevel ); self::_pushResponseStack( $level ); } if( !is_null($loggerName) ){ self::_pushResponseStack( '<b>【'.$loggerName.'】 </b>' ); } switch( true ){ //STRING case is_string($mixedValue): self::_pushResponseStack( self::_getTypeSpan('STRING').nl2br(htmlspecialchars($mixedValue)) ); break; //INT case is_int($mixedValue): self::_pushResponseStack( self::_getTypeSpan('INT').$mixedValue ); break; //FLOAT case is_float($mixedValue): self::_pushResponseStack( self::_getTypeSpan('FLOAT').$mixedValue ); break; //BOOL case is_bool($mixedValue): $mixedValue ? $mixedValue = 'TRUE' : $mixedValue = 'FALSE'; self::_pushResponseStack( self::_getTypeSpan('BOOL').$mixedValue ); break; //NULL case is_null($mixedValue): self::_pushResponseStack( 'NULL' ); break; //ARRAY case is_array($mixedValue): self::_pushResponseStack( self::_getTypeSpan('ARRAY') ); self::_pushResponseStack( '<ul>' ); foreach ($mixedValue as $key => $value) { self::_pushResponseStack( '<li>'.self::_getListKeySpan($key).' ' ); self::dump($value,null,null,( is_array($value) || is_object($value) ),$traceObjectMethods); self::_pushResponseStack( '</li>' ); } self::_pushResponseStack( '</ul>' ); break; //Exception case ( $mixedValue instanceof Exception ): self::_pushResponseStack( '<span class="toydebug_color_exception">'.get_class($mixedValue).'</span>' ); self::_pushResponseStack( '<ul>' ); self::_pushResponseStack( '<li><span class="toydebug_color_exception_item"> MESSAGE </span> '.htmlspecialchars($mixedValue->getMessage()).'</li>' ); self::_pushResponseStack( '<li><span class="toydebug_color_exception_item"> FILE </span> '.htmlspecialchars($mixedValue->getFile()).' ( LINE:'.$mixedValue->getLine().' )</li>' ); self::_pushResponseStack( '<li><span class="toydebug_color_exception_item"> TRACE </span> ' ); self::dump($mixedValue->getTrace(),null,null,true,false); self::_pushResponseStack( '</li>' ); self::_pushResponseStack( '</ul>' ); break; //OBJECT case is_object($mixedValue): $className = get_class($mixedValue); self::_pushResponseStack( 'CLASS :: '.$className ); if( $traceObjectMethods ){ $methods = get_class_methods($mixedValue); if( !is_null($methods) ){ self::_pushResponseStack( '<ul>' ); foreach ($methods as $method_name) { self::_pushResponseStack( '<li>[METHOD] '.htmlspecialchars($method_name).'</li>' ); } self::_pushResponseStack( '</ul>' ); } } $vars = get_object_vars($mixedValue); if( !is_null($vars) ){ self::_pushResponseStack( '<ul>' ); foreach ($vars as $key => $value) { if( !is_object( $value ) ){ self::_pushResponseStack( '<li>[VARS] $'.htmlspecialchars($key.' ⇒ '.$value).'</li>' ); }else{ self::dump($value,$key,null,true,false); } } self::_pushResponseStack( '</ul>' ); } break; //OTHER TYPE default: self::_pushResponseStack( htmlspecialchars($mixedValue) ); break; } if( $isEchoDiv ){ self::_pushResponseStack( '</div>' ); } } /** * Debug用のCSSを出力します * @return void */ private static function _echoDebugCss(){ if( self::$_cssEchoed ){ return; } echo ' <style type="text/css"> <!-- div.toydebug { margin:5px; margin-left:30px; background-color:#FFFFCC; border:solid 1px #666666; padding:3px; } div.toydebug ul{ margin-left:0px; } div.toydebug li{ list-style-type:none; margin-left:0px; } div.toydebug span.toydebug_type{ color:#3366FF; } div.toydebug span.toydebug_list_key{ color:#FF0000; } .toydebug_color_debug{ background-color:#339900; color:#FFFFFF; font-weight:bold; width:80px; } .toydebug_color_info{ background-color:#0066FF; color:#FFFFFF; font-weight:bold; width:80px; } .toydebug_color_warn{ background-color:#FF0000; color:#FFFFFF; font-weight:bold; width:80px; } .toydebug_color_fatal{ background-color:#FF0000; color:#FFFFFF; font-weight:bold; width:80px; } .toydebug_color_error{ background-color:#FF0000; color:#FFFFFF; font-weight:bold; width:80px; } .toydebug_color_exception{ background-color:#FF0000; color:#FFFFFF; font-weight:bold; min-width:80px; } .toydebug_color_exception_item{ background-color:#666699; color:#FFFFFF; font-weight:bold; min-width:80px; } --> </style>'; self::$_cssEchoed = true; } /** * Stackに追加します * @param mixed $pushStr */ private static function _pushResponseStack( $pushStr ){ self::$_responseStack .= $pushStr; } /** * デバッグレベルの表示用ラベルを取得します * @param int $debugLevel * @return string */ private static function _getDebugLevelLabel( $debugLevel ){ switch( $debugLevel ){ case Toytools_Debug::LEVEL_DEBUG; $cssStyleClass = 'toydebug_color_debug'; $levelLabel = 'DEBUG'; break; case Toytools_Debug::LEVEL_INFO; $cssStyleClass = 'toydebug_color_info'; $levelLabel = 'INFO '; break; case Toytools_Debug::LEVEL_WARN; $cssStyleClass = 'toydebug_color_warn'; $levelLabel = 'WARN '; break; case Toytools_Debug::LEVEL_ERROR; $cssStyleClass = 'toydebug_color_fatal'; $levelLabel = 'ERROR'; break; case Toytools_Debug::LEVEL_FATAL; $cssStyleClass = 'toydebug_color_error'; $levelLabel = 'FATAL'; break; default: throw new Exception('Toytools_Debug_Core::_getLevelStyleClassName'); break; } return '<span class="'.$cssStyleClass.'"> '.$levelLabel.' </span> '; } private static function _getTypeSpan( $typeName ){ return '<span class="toydebug_type">['.$typeName.']</span> '; } private static function _getListKeySpan( $typeName ){ return '<span class="toydebug_list_key">['.$typeName.']</span> '; } } ?>