[Firebug](http://getfirebug.com/) jest już obowiązkowym dodatkiem do Firefoxa dla każdego webdevelopera. Jest on wręcz niezbędny i osobiście nie wyobrażam sobie pracy z css-em bez niego. Jako programista produkujący skrypty wykonywane raczej po stronie serwera oczywiście doceniam jego użyteczność, ale dopiero w połączeniu z [FirePHP](http://www.firephp.org/) popadam w euforię ;).
Przy okazji tylko wspomnę, że istnieje odpowiednik FirePhp dla Pythona [FirePy](http://code.google.com/p/firepy/wiki/Documentation), Ruby, Perla i paru jeszcze innych języków o czym można się przekonać wchodząc na stronę [wiki projektu](http://www.firephp.org/Wiki/). W tym samym miejscu przekonamy się, że FirePHP lub jego odpowiedniki został już zintegrowany z całą masą co bardziej popularnych frameworków i aplikacji jak np. Zend Framework, Symfony, Kohana, Typo3, Prado, Seagull, WordPress, eZ itd. Nie dziwi to gdyż jak się sam przekonałem użycie FirePhp jest wręcz banalne.
Wziąwszy pod uwagę wielkość [dokumentacji użycia](http://www.firephp.org/HQ/Use.htm) ograniczającą się do jednej, niewielkiej strony, można by pomyśleć, że FirePHP nie jest zbyt imponującą biblioteką albo jest kiepsko udokumentowana. Okazuje się, że funkcjonalność FirePHP jest rzeczywiście ograniczona, ale jest to ograniczenie w sensie pozytywnym. Znajdziemy tu tylko to, co jest naprawdę przydatne. I tak mamy:
* możliwość wielopoziomowego (log, info, warn, error) logowania danych do konsoli Firebuga – możemy też dane przedstawić w formie tabeli.
* możliwość zrzutu danych prezentowanego w zakładce „sieć” Firebuga
* możliwość włączenia errorhandlera i exceptionhandlera przechwytujących błędy i wyjątki php i logujących je do konsoli Firrebuga
* możliwość wyświetlenia backtrace-a
FirePHP nie jest pozbawiony błędów lub raczej niedoskonałości, które ujawniają się w trakcie próby przesłania zbyt wielkiej liczby danych lub zbyt długo trwającej rekurencji dlatego też boję się oprzeć swojego debuggera jedynie o ten dodatek. Z drugiej strony podoba mi się np. [firebug_profiler](http://github.com/nickdunn/firebug_profiler) do CMS-a Symphony napisany przez Nicka Dunna, co skłania mnie do eksperymentowania z tym dodatkiem i badania granic jego przydatności.
Na razie ograniczam użycie FirePHP do bieżącego debugowania aplikacji. Dotychczas chcąc szybko wyświetlić zawartość jakieś zmiennej używałem var_dump-a. Ponieważ użycie var_dump-a w wielu miejscach rodziło pewne problemy z jego późniejszym odszukaniu zdefiniowałem sobie w Eclipsie taki mały snippet, który oprócz właściwej zmiennej wyświetlał też nazwę pliku oraz linię w której var_dump został wywołany. Wyglądało to mniej więcej tak:
var_dump('FILE:'.__FILE__. ' LINE:'.__LINE__, $var); //DEBUG |
var_dump('FILE:'.__FILE__. ' LINE:'.__LINE__, $var); //DEBUG
Zważywszy, że snippet wywoływany był za pomocą skrótu klawiaturowego dodawanie ‚FILE:’.__FILE__. ‚ LINE:’.__LINE__ nie było zbyt upierdliwe, jednak postanowiłem tę kwestię rozwiązać w bardziej elegancki sposób.
class Logger
{
private static $_firePhp;
public static function log($object, $label = null)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->log($object, $label);
$_fb->groupEnd();
}
public static function warn($object, $label = null)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->warn($object, $label);
$_fb->groupEnd();
}
public static function info($object, $label = null)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->info($object, $label);
$_fb->groupEnd();
}
public static function error($object, $label = null)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->error($object, $label);
$_fb->groupEnd();
}
public static function table($label, $table)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->table($label, $table);
$_fb->groupEnd();
}
public static function dump($key, $variable)
{
$_fb = self::_getFirePhp();
$_fb->dump($key, $variable);
}
private static function _getFirePhp()
{
if (is_null(self::$_firePhp)) {
require_once('FirePHPCore/FirePHP.class.php');
$_firephp = FirePHP::getInstance(true);
$_options = array('maxObjectDepth' => 10,
'maxArrayDepth' => 20,
'useNativeJsonEncode' => true,
'includeLineNumbers' => true);
$_firephp->setOptions($_options);
self::$_firePhp = $_firephp;
}
return self::$_firePhp;
}
private static function _prepareMetaData()
{
$_level = 1;
try {
throw new Exception();
} catch (Exception $_e) {
$_trace = $_e->getTrace();
return sprintf('FILE: %s LINE %s TIME %s'
, $_trace[$_level]['file']
, $_trace[$_level]['line']
, date("h:i:s", time()));
}
}
} |
class Logger
{
private static $_firePhp;
public static function log($object, $label = null)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->log($object, $label);
$_fb->groupEnd();
}
public static function warn($object, $label = null)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->warn($object, $label);
$_fb->groupEnd();
}
public static function info($object, $label = null)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->info($object, $label);
$_fb->groupEnd();
}
public static function error($object, $label = null)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->error($object, $label);
$_fb->groupEnd();
}
public static function table($label, $table)
{
$_fb = self::_getFirePhp();
$_label = self::_prepareMetaData();
$_fb->group($_label);
$_fb->table($label, $table);
$_fb->groupEnd();
}
public static function dump($key, $variable)
{
$_fb = self::_getFirePhp();
$_fb->dump($key, $variable);
}
private static function _getFirePhp()
{
if (is_null(self::$_firePhp)) {
require_once('FirePHPCore/FirePHP.class.php');
$_firephp = FirePHP::getInstance(true);
$_options = array('maxObjectDepth' => 10,
'maxArrayDepth' => 20,
'useNativeJsonEncode' => true,
'includeLineNumbers' => true);
$_firephp->setOptions($_options);
self::$_firePhp = $_firephp;
}
return self::$_firePhp;
}
private static function _prepareMetaData()
{
$_level = 1;
try {
throw new Exception();
} catch (Exception $_e) {
$_trace = $_e->getTrace();
return sprintf('FILE: %s LINE %s TIME %s'
, $_trace[$_level]['file']
, $_trace[$_level]['line']
, date("h:i:s", time()));
}
}
}
Jak widać do wyłuskania meta danych użyłem wyjątku. Szybka analiza stacktracea i w miarę prosty sposób uzyskałem informację o miejscu wywołania loggera. Teraz wyświetlając jakąś zmienną w konsoli FireBuga wiem nie tylko o tym co ta zmienna zawiera, ale też w sytuacji, w której zapomniałbym o usunięciu tymczasowego wpisu, mogę łatwo go odnaleźć i naprawić swoje niedopatrzenie 😀