Gestion personnalisée
des exceptions PHP

La version 5 de PHP apporte une gestion des exceptions similaires à ce qu'offrent d'autres langages de programmation. On peut ainsi lancer une exception (throw) qui sera éventuellement attrapée (catch) et traitée. On peut ainsi entourer du code sensible de structures try et catch, avec pour chaque structure try une structure catch correspondante.

L'exception n'a rien à voir avec une simple erreur. Lorsqu'une exception est lancée, le flot du programme est interrompu jusqu'au premier bloc catch, ou s'il n'y en a pas, jusqu'au gestionnaire d'exceptions. Ce qui veut dire qu'il nous appartient de gérer l'exception, et de l'attraper si on prévoit une solution de rechange à notre code de test.

Ce billet s'intéressant essentiellement à la personnalisation des exceptions PHP, pour de plus amples informations sur les exceptions je vous invite à consulter la documentation PHP sur les exceptions, et surtout l'excellent billet de Fabrice Lezoray : PHP 5 et la gestion des exceptions.

Quand à moi, je vais vous présenter la classe WdException qui permet de lancer des exceptions tout en profitant des fonctionnalités de la classe WdDebug, et notamment des rapports d'incidents. Je vous invite également à découvrir le framework WdCore, duquel est issue la classe.

Présentation de la classe WdException

La classe WdException peut être utilisée pour lancer des exceptions. Elle étend la classe Exception et présente les fonctionnalités suivantes :

  • Le message de l'exception est formaté et localisé (traduit) grâce à la classe WdLocale.
  • Le message de l'exception est formaté de manière similaire aux erreurs personnalisées par la classe WdDebug.
  • Les messages issus de la journalisation de la class WdDebug peuvent être ajoutés au message de l'exception.
  • Un rapport d'incident peut être émit.

La classe est aussi simple à mettre en ouvre que la classe WdDebug :

<?php

define('WDDEBUG_SILENT'true);
define('WDDEBUG_REPORT_ADDRESS''me@mycompany.com');
define('WDEXCEPTION_WITH_LOG'true);

require_once 'wdexception.php';

set_exception_handler(array('WdDebug''exceptionHandler');

Voyons ce que cela donne avec un petit exemple.

Un exemple d'exception, mais pas exceptionnel

L'exemple suivant présente une fonction test() qui ne supporte pas que son paramètre $a soit différent de 1. Cela l'ennui tellement qu'elle ne se prive pas de lancer une exception si cela se produit :

<?php

function test($a)
{
    if ($a != 1)
    {
        throw new WdException('$a must be 1, %value given instead'array('%value' => $a));
    }
}

wd_log('A little message before the big crash');

test(13);

On notera, juste avant l'appel à la fonction test(), un appel à la fonction wd_log(). Cette fonction est une des fonctions de journalisation non intrusives proposées par la classe WdDebug. Les messages loggés par cette fonction sont ajoutés au message d'exception si la constante WDEXCEPTION_WITH_LOG est définie comme vraie.

Voyons maintenant le résultat de ce test :

Exception with the following message:

$a must be 1, 13 given instead

in G:\Weirdog\www\wd\_test\debug.php at line 19

Stack trace:

#00 — /debug.php(25): test(13)

Log:

A little message before the big crash

À noter que si la constante WDDEBUG_REPORT_ADDRESS est définie, le message de l'exception nous parviendra par E-Mail. De quoi réagir bien vite avant que cela ne pose trop de problèmes.

Attraper le bon type d'exception

Un dernier petit mot sur les blocs try et catch, parce que ce n'est pas très clair dans la documentation. Lorsque l'on crée un bloc catch, le type d'objet définit le type d'exception qui peut être attrapé par le bloc. Ceci est très important, et pratique, puisque l'on peut sélectionner le type d'exception à attraper, mais cela peut également être problématique si on ne fait pas attention à ce que l'on fait :

<?php

try
{
    test(13);
}
catch (OtherException $e)
{
    echo 'je suis complètement ignoré !';
}
catch (Exception $e)
{
    echo 'ça tombe sur moi par erreur';
}
catch (WdException $e)
{
    echo 'ça devrait tomber sur moi';
}

Ce qui nous donne :

ça tombe sur moi par erreur

En arrangeant l'ordre des blocs on peut récupérer l'exception qui nous intéresse :

<?php

try
{
    test(13);
}
catch (OtherException $e)
{
    echo 'je suis complètement ignoré !';
}
catch (WdException $e)
{
    echo 'ça devrait tomber sur moi';
}
catch (Exception $e)
{
    echo 'ça tombe sur moi par erreur';
}

Ce qui nous donne :

ça devrait tomber sur moi

Aller plus loin dans la personnalisation

Le gestionnaire d'exception proposé par la classe WdDebug ne se fatigue pas trop dans la présentation du message. Un petit coup de echo et le tour est joué, mais on peut en faire un peu plus. Voici par exemple le gestionnaire d'exception de WdPublisher, qui utilise un patron HTML pour présenter l'exception :

<?php

class WdPCore
{
    static public function exceptionHandler($exception)
    {
        $html = file_get_contents('exception.html'true);
        
        $html = str_replace('{publisher.url}', WDPUBLISHER_URL, $html);
        $html = str_replace('{exception.body}'$exception$html);
        
        echo $html;
        
        exit;
    }
}

On se retrouve ainsi avec une page HTML des plus classe pour présenter notre exception :

Exception

En vous souhaitant du courage

Bon, j'espère que les classes WdDebug et WdException vous rendrons bien service et vous serons aussi utile qu'à moi.

Débuggez bien !

Laisser un commentaire

Pas de commentaire