Debug PHP facile avec Firefox, Firebug et FirePHP
Par NiKo le dimanche 20 juillet 2008, 11:39 - Dev
- Lien permanent -
20 commentaires -
Tags :
Tous ceux qui ont déjà eux à batailler avec du code javascript connaissent certainement la fabuleuse extension Firebug pour Firefox. L'outil propose une console permettant d'examiner l'environnement d'exécution javascript mais aussi HTML et CSS de n'importe quelle page web.
FirePHP est une autre extension qui a pour but de proposer le même service mais pour le langage PHP. L'extension repose elle-même sur Firebug et propose, une fois installée, l'affichage dans la console des messages de debug émis depuis vos scripts PHP :

Une fois l'extension Firefox installée, pour pouvoir envoyer un message de log dans la console depuis vos scripts, il faut utiliser une librairie spécifique PHP fournie téléchargeable depuis la page d'accueil du projet FirePHP. Cette librairie très simple est d'ailleurs documentée ici. Une fois l'archive récupérée, décompressez-la et appelez FirePHP de cette façon depuis un script PHP standard :
require_once '/path/to/firephp/lib/FirePHPCore/FirePHP.class.php'; $f = FirePHP::getInstance(true); $f->fb('Hello FirePHP console', FirePHP::INFO); $f->fb(array('hello' => 'how are you?')); $f->fb(array('hello' => array('how', 'are', 'you'))); $f->fb(array('foo', 'bar'), 'Results', FirePHP::WARN); $o = new stdClass(); $o->foo = 'foofoo'; $o->bar = 'barbar'; $f->fb($o);
Pour envoyer les informations de debug à la console, la librairie PHP envoie les données sérialisées au format JSON dans un entête HTTP personnalisé dédié (X-FirePHP-Data). Ainsi, aucune interférence n'est possible avec vos scripts existants, la seule condition étant bien entendu de ne pas lancer la sortie standard PHP avant que ces entêtes aient été envoyés.

En bref, un outil génialement simple et efficace.
20 commentaires (Ajouter un commentaire)
Même pas un petit mot sur l'extension symfony qui va avec ?
Geoffrey> J'aime pas trop "l'intégration" qui a été faite. En plus l'extension symfony n'apporte rien de plus aux fonctionnalités de base
Je l'avais essayé il y a un moment déjà et l'utilité me paraissait limitée : qu'est-ce que cela apporte de plus qu'un traditionnel var_dump ou un die intelligemment posés ? (autrement dit, il est vrai, n'importe où pour peu qu'on puisse les voir)
Pour moi, cela se limitait à me faire écrire des lignes en plus.
Il y a du travail en cours au niveau de l'intégration de FirePHP au sein du Zend Framework, par le biais d'un Log_Writer :
http://framework.zend.com/wiki/disp...
Avec comme avantages le fait que ça doit pouvoir se brancher à la place d'un autre système de logging, tant qu'il est basé sur Zend_Log.
Et - en réponse au premier commentaire et à un sujet qui revient souvent sur ce blog - une idée pour le futur est de passer à une barre du genre de celle de Symfony ^^
(il y a quelques notes intéressantes, à ce sujet comment à d'autres, au niveau de la section "Future" du lien donné plus haut)
Jawad > c'est non-intrusif ? (ça ne met pas des infos à l'écran, qui viennent potentiellement exploser la mise en page ; tes infos de debug sont séparées du contenu de la page, aussi ; il faudrait que j'essaye, mais ça doit permettre d'inclure des infos de debug sur une page non HTML (typiquement, en générant une image ou un pdf à la volée))
Après, je n'ai pas encore assez utilisé pour "être fan" - ou pas ^^
J'aurais tendance à dire comme Jawad : de ce que je comprends, il faut explicitement indiquer des sorties spécialement pour firephp. Si tu dois modifier ton code à chaque fois que tu utilise firephp, ça peut être problématique amha (oubli de supprimer les traces, modification de comportement de code, etc)
Au moins dans le cas de javascript avec firebug, ton code js n'est pas altéré... (bon c'est vrai qu'avec un code exécuté/disponible coté client, c'est plus simple que pour du code exécuté coté serveur...)
Je vois donc pas l'intérêt du truc (hormis que ça pollue pas ta page générée de ton application)
NiCos et Jawad: Vous avez bu les mecs ?
L'intérêt est évident, c'est du débugging non-obstrusif. Vous pouvez décoreller les logs du support, du medium. Genre débugguer un webservice XML ou JSON, entre autres. Et c'est beaucoup plus sexy à la consultation qu'un fichier de logs en plus, non ?
Je ne vous parle même pas des capacités d'introspection des objets... Nan, vous êtes vraiment sérieux, vous voyez pas l'intérêt de tels outils ?
PS: NiCoS> un simple système d'abstraction de logger et de gestion d'environnement (debug à true/false comme en Django, ça te parle ?) suffirait à régler le problème que tu soulèves.
Ca me semble assez génial sur le principe comme outil, mais il y a un point problématique qui me dérange dans le système :
Pour utiliser cette extension il est nécessaire d'insérer dans le script PHP des instructions spécifiques pour le debug (déjà rien que pour charger la librairie associée). Cela à évidemment un coût au niveau de la "lourdeur" du script entre autre, et puis on peut imaginer que l'insertion d'une librairie supplémentaire à un script PHP ajoute également un risque de bugs (personne n'est parfait, et tout script comporte potentiellement des bugs), ou de confits etc...
Du coup, dans un souci d'optimisation, il est nécessaire de faire un nettoyage supplémentaire lors de la mise en prod du script. Manipulation qui ajoute elle aussi un risque d'erreur et donc de bug, qu'il ne sera du coup pas détectable via l'outil firephp, évidemment.
Ce problème soulève donc une question : Cela vaut-il la peine de dépenser du temps, d'ajouter des risques de bugs, et de perdre en optimisation, uniquement dans le but d'avoir un affichage plus sexy des messages de debug ?
Une autre question qui découle de tout ça : Y aurait-il une solution propre pour coder de manière a pouvoir facilement exploiter cette extension (ou d'autres solutions de debug semblables), tout faisant facilement disparaître les fonctions de debug lors de la mise en prod pour optimiser les scripts ?
Bon, vous avez gagné, voila de quoi vous en sortir en terme d'abstraction d'environnement, avec un petit pattern factory en prime :
<?php interface Loggable { public function log(); } class myLogger { protected static $loggers = array(); public static function create($type, $debug) { if (true !== $debug) { $type = 'No'; } if (!array_key_exists($type, self::$loggers)) { $class = sprintf('my%sLogger', $type); if (!class_exists($class, true)) { throw new InvalidArgumentException(sprintf('Class "%s" does not exist', $class)); } if (!new $class() instanceof Loggable) { throw new InvalidArgumentException(sprintf('Class "%s" does not implements Loggable interface', $class)); } self::$loggers[$type] = new $class(); } return self::$loggers[$type]; } } class myNoLogger implements Loggable { public function log() { return; } } class myFileLogger implements Loggable { public function log() { $args = func_get_args(); file_put_contents(dirname(__FILE__).'/my_php_log.log', var_export($args, true)); } } class myFirePHPLogger implements Loggable { public function log() { $args = func_get_args(); $f = FirePHP::getInstance(true); call_user_func_array(array($f, 'fb'), $args); } }Utilisation :
// En dev $debug = true; // Dans FirePHP myLogger::create('FirePHP', $debug)->log('toto', 'tata'); // Dans un bête fichier de log myLogger::create('File', $debug)->log('toto', 'tata'); // En prod $debug = false; // Là il ne se passe rien, puisque le debug est désactivé myLogger::create('FirePHP', $debug)->log('toto', 'tata'); // Là il ne se passe rien, puisque le debug est désactivé myLogger::create('File', $debug)->log('toto', 'tata');Bien entendu, c'est à peaufiner, et on imaginera que la variable
$debuget le type de logger sont définis dans un fichier de conf externe (qui ne sera pas versionné). Le must étant bien entendu de dégager le paramètre$debugde la méthodecreatede la classemyLoggerpour qu'il soit récupéré automatiquement, mais j'avais la flemme (mais c'est possible).Pour compléter mon commentaire précédent :
Le point qui me semble le plus intéressant dans le fonctionnement de firePHP est l'envoi des messages d'erreur (ou warn, info etc...) dans l'entête HTTP au lieu de les intégrer dans le contenu de la réponse.
Avec ce mode de fonctionnement pour les messages d'erreurs, l'exploitation qui est faite des erreurs importe peu : On peut utiliser FirePHP, mais on pourrait envisager d'autre outils (qui pourraient être indépendant du navigateur, ou associés à d'autres navigateurs), et cela est très intéressant. Le mieux étant de mettre en place une norme concernant cet envois de messages par entête HTTP afin d'avoir une solution interopérable.
Du coup, le point le plus important est justement la manière dont les messages PHP/HTTP sont envoyés. Or ici, la solution utilisée ne me semble pas la meilleur (mais j'ai pas étudié en détail, je me base uniquement sur la présentation que tu en fait ici) : Il est nécessaire d'appeler des fonctions/librairies spécifiques pour envoyer des messages dans le header HTTP. C'est plutôt intrusif comme solution, et pour un programmeur soucieux de l'optimisation, de la propreté et de l'indépendance (indépendance par rapport à des librairies/technologies etc.) de ses script, c'est pas génial.
Une solution peut-être plus intéressante aurait été d'utiliser les capacités de gestion d'exceptions de PHP (PHP > 5 il me semble, donc effectivement avant PHP 5, c'est peut-être pas exploitable). De cette manière, si je ne m'abuse, il est possible de n'avoir qu'a remplacer le gestionnaire d'exception PHP par le gestionnaire firePHP, et cela serait moins intrusif dans les script, non ? Toute erreur, ou tout message serait envoyé au gestionnaire d'exception, qui se chargerait, si c'est le gestionnaire firePHP qui est chargé, d'envoyer les message en HTTP. Et lors du passage en prod, il suffit alors d'utiliser un autre gestionnaire d'exception qui n'envoie pas les message en HTTP et c'est réglé. Cela oblige par contre à programmer en utilisant l'envoi d'exception.... mais c'est plutôt une bonne habitude à prendre, non ?
Est-ce que ce que je raconte est complètement loufoque, ou trouvez-vous cela plutôt sensé ? (dans ce cas il serait intéressant d'en faire la suggestion aux développeurs de firePHP)
Nico> Une exception n'est pas forcément une erreur. Ce constat m'a d'ailleurs posé pas mal de souci à une époque : http://prendreuncafe.com/blog/post/...
"Une exception n'est pas forcément une erreur"
Mais un message de debug n'est pas non plus forcement une erreur....
J'avoue ne pas être spécialiste de la question, mais je ne vois pas bien le problème que poserait un outil de debug qui exploiterait les exceptions. Le post que tu cite ne m'éclaire pas vraiment, je manque de connaissance pour voir clairement les choses.
Donc d'après toi l'utilisation des exceptions ne serait pas une bonne solution ?
Non. Tu peux utiliser les exceptions pour sortir d'un état, d'une méthode... Pour plein de trucs en fait. Par contre, tu peux typer les exceptions, ou utiliser des exceptions standards représentant des erreurs, comme celles de la SPL (
InvalidArgumentException,LogicException, etc.)Dans l'exemple que je te donne, symfony envoie une
sfStopExceptionpour notifier la chaîne de filtres qu'il faut l'arrêter et rendre la répnse immédiatement. Ce n'est clairement pas une erreur, mais bien un comportement voulu par le programmeur. Un autre exemple, une validation de formulaire avec symfony 1.1 : en cas de champs non conforme à ce qui est attendu, unesfValidationErrorétendant la classeExceptionest envoyée : c'est une erreur de validation, mais est-ce pour autant une erreur de programmation ? Tu vois la nuance ?Pour résumer, certaines exceptions représentent des erreurs, mais pas toutes, donc les attraper toutes n'est pas forcément parlant pour débugguer.
Niko : je vois l'intérêt dans l'absolu (comme le dit mon dernier bout de commentaire). C'est le coté "intrustif" de firephp qui me chifonne un peu, un peu dans le sens de Nico (encore un ?).
Quand je vois ce que nous livre des SSII ayant pignon sur rue, si les ajouts de code pour FirePHP sont mal gérés, j'ai peur pour les livraisons et ce qui va partir en prod.
D'ailleurs question : imaginons qu'un dev laisse des traces pour FirePHP sur un environnement de prod. Si j'ai FirePHP installé sur ma machine (et suis extérieur au projet en prod), je peux récupérer tout ce qui passe ?
Si oui, ça craint et ça impose de pouvoir distinguer absolument les environnements sous pein de grosses cata (au hasard, pour des traces liés à des transactions bancaires...)
Ok, je viens d'installer FirePHP (pff quelle idée de demander un compte pour une extension "expérimentale", une simple boite à cocher suffirait... ah la collecte d'info... du coup, j'ai pris la preview de firephp), il faut déclarer les sites, donc sauf à ajouter tous les sites sur lequel on passe, il y a peu de chances de profiter des traces laissées par inadvertance...
Ah c'est très très bon ça !
J'utilise PEAR::log et son gestionnaire firebug mais le fait d'utiliser les headers HTTP c'est beaucoup plus facile à gérer étant donné qu'on n'est pas obligé d'attendre la sortie pour balancer les messages (en + ça sort en javascript... donc ne marche que si on sort du HTML et qu'on évalue le javascript). Effectivement pour tout ce qui est service web et ajax voilà une solution sal-va-tri-ce !!!.
niko merci, je test, ça va être pratique
Ce qui me parait effectivement le plus intéressant, et le plus convaincant, c'est de pouvoir obtenir une trace même dans un contexte où il n'y a pas d'affichage possible simplement (exemple: suite à une requête AJAX où, pour utiliser un var_dump, cela n'est pas évident).
Poser des var_dump ou des die n'a jamais été d'une propreté exemplaire, mais cela reste souvent plus simple et plus rapide que n'importe quel autre outil.
J'utilise cette extension assez intensivement depuis quelques semaines et ça m'a changé la vie . Bon pas tant que ça mais je me fait moins suer.
Ceci comme cela a déjà été dis, c'est pratique pour les requête ajax les flux xml etc... avec la fonction fb() cela prend à peine plus de code qu'un var_dump, et c'est à mon avis bien plus puissant puisque la sortie est plus facile à lire et ça c'est inestimable.
Comme j'utilise dojo, j'ai accès à une console de débogage qui couvre la totalité de mon application et c'est vraiment utile.
Ce n'est certe pas indispensable, mais tellement confortable que je pense que j'aurai du mal à m'en passer.
Hi all,
Sorry about my english post but I don't speak french.
I quite enjoyed reading all the comments (via google language tools :)). I would love to continue this discussion in the FirePHP discussion group if anyone is interested.
http://groups.google.com/group/Fire...
Please join to discuss the current functionality and explore future uses. I would love to get some support from the symfony community to develop a comprehensive plugin that integrates with many aspects of the framework.
My goal is to develop a debug bar similar to the current symfony debug bar that is cross-framework and eventually cross-browser. It would be great to develop this for symfony and Zend Framework in parallel to ensure that there are no framework specific design decisions made.
I look forward to your feedback and thanks for your interest.
Christoph
Hi Christoph !
Thanks for beeing here, I'm honoured
I should really write my technical posts in english, but I'm so lazy, sorry for that...
We're planning to propose the FirePHP console as an alternative to the current web debug toolbar in the next version of symfony, I'd be more than happy to collaborate with the FirePHP community to ensure consistency regarding our intergation
I've just subscribed to your group.