IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Exceptions et PHP5

Exceptions et PHP5


prcdentsommairesuivant

III. Exceptions ou erreurs ?

Dans ce paragraphe, nous allons comparer les 2 systmes (exceptions/erreurs). En fait, nous allons nous concentrer sur les exceptions qui est le sujet principal, car on remarquera vite que les inconvnients de l'un sont les avantages de l'autre et rciproquement.

III-A. Avantages des exceptions

III-A-1. Lisibilit

Comme je l'ai dj crit plusieurs fois, les exceptions ne sont pas identiques aux erreurs dans le sens ou elles reprsentent un fonctionnement normal, mais exceptionnel. Nous allons maintenant voir un exemple dans lequel les exceptions nous aident grandement et montrent clairement que le mcanisme de gestion d'erreurs n'a rien voir l-dedans. Considrons une page de traitement de formulaire d'inscription un site. Nous avons le pseudo, le mot de passe et la confirmation ainsi que l'adresse mail qui arrivent du formulaire. Il faudra vrifier que le pseudo n'existe pas, que le mot de passe et la confirmation sont identiques et que le mail est correct.

On pourrait y arriver avec une avalanche de if, mais a deviendrait vite suffisamment compliqu pour qu'une erreur s'y glisse. Par exemple :

Page d'inscription utilisant une avalanche de if
Sélectionnez

$result = mysql_query("
    SELECT 1 FROM membres 
    WHERE login='".mysql_real_escape_string($_POST['login'])."'");
 
if (mysql_num_rows($result) == 0)
{
    // le pseudo n'est pas pris, on continue
    if ($_POST['pass'] == $_POST['confirmation'])
    {
        // Le mot de passe et la confirmation concident
        if (isValide($_POST['mail']))
        {
            // Le mail est valide, on insre le mebre
            insere_membre($_POST['login'], $_POST['pass'], $_POST['mail']);
        }
        else
        {
            affiche_formulaire('mail_invalide');
        }    
    }
    // Le mot de passe et la confirmation ne concident pas
    else
    {
        affiche_formulaire('error_mdp');
    }
}
// Le pseudo est pris, on affiche le formulaire
else
{
    affiche_formulaire('error_login');
}

Imaginez si on doit effectuer une vrification sur 200 champs de fomulaire. C'est sincrement ingrable cause de la profondeur des if.

Grce aux exceptions, on ne s'enfonce plus dans une telle profondeur de if, et on n'appelle plus qu'une seule fois la fonction affiche_formulaire. Ainsi, le code prcdent devient :

Page d'inscription utilisant les exceptions
Sélectionnez

try
{
    $result = mysql_query("
        SELECT 1 FROM membres 
        WHERE login='".mysql_real_escape_string($_POST['login'])."'");
 
    if (mysql_num_rows($result) > 0)
    {
        throw new Exception('error_login');
    }
 
    if ($_POST['pass'] != $_POST['confirmation'])
    {
        throw new Exception('error_mdp');
    }
 
    if ( ! isValide($_POST['mail']))
    {
        throw new Exception('mail_invalide');
    }
}
catch(Exception $myException)
{
    affiche_formulaire($myException->getMessage());
}

III-A-2. Fiabilit

Les exceptions permettent de ne pas stopper net un systme ayant gnr une erreur. Ceci permet d'effectuer un traitement adapt au problme rencontr, voire parfois de le rparer. Ainsi, certains langages comme l'ADA ont intgr entirement les exceptions dans leur langage pour grer les erreurs lies au systme. C'est pourquoi l'ADA est trs utilis en milieu militaire et arospatial. En effet, mme dans ces systmes coutnt des milliards, il y a des bugs, des erreurs... Il vaut donc mieux tre sr que mme en cas d'erreur, le systme ne va pas simplement s'arrter. Java, bien que possdant une gestion des erreurs, est trs orient exception, ce qui a contribu (entre autre) son succs dans le monde industriel. Une classe Java annonce quelles exceptions elle lance. Ainsi, un code source Java ne traitant pas ces exceptions n'est simplement pas compil. Tous les autres langages utilisent soit les erreurs uniquement, soit un rpartition quilibre entre exception et erreur.
Evidemment, pour augmenter rellement la fiabilit des systmes, il est important de bien rflchir la cohrence des classes d'exception et de bien les capturer. Sinon, le systme ne correspondra qu' une gestion des erreurs traditionnelles.

III-B. Inconvnients des Exceptions

III-B-1. Implmentation "partielle"

Dans PHP5, le mcanisme d'exception est totalement oprationnel, mais ne constitue qu'un apport pour le dveloppeur et non pour le langage. C'est dire que PHP5 n'utilise pas les exceptions. L'ensemble des fonctions de PHP gnrent toujours des erreurs PHP lorsqu'elles rencontrent un problme, seules quelques extensions ont adopt le modle des exceptions. Cette faible prsence des exceptions dans PHP5 s'explique par :

  • La programmation objet en PHP n'a de rel sens que depuis PHP5 or, pour utiliser au mieux les exceptions, il est ncessaire pour un langage de possder un bon modle objet.
  • Lorsqu'une exception est souleve, le contexte local contenu dans un bloc try est sauvegard, ceci peut tre amplifi par l'imbrication de bloc try. L'abus de l'utilisation des exceptions peut donc diminuer considrablement les performances.
  • Par choix. La plupart des langages choisissent de ne pas supprimer la gestion des erreurs au profit des exceptions pour des raisons de performances et de style de programmation (les exceptions sont quivalentes pour certains programmateurs l'affreux goto, de plus les exceptions augmentent considrablement le nombre de lignes de code). D'autres langages, comme l'ADA, n'utilisent que les exceptions.

III-B-2. Boucle infinie

Les exceptions permettent un traitement personnalis d'une erreur. Imaginons un systme d'exception unique pour tout un script, que le dveloppeur utilise pour fiabiliser l'accs un fichier, la connexion une BDD... Dans cette classe d'exception, il dcide de logguer toutes les exceptions souleves afin de garder une trace. Pour cela, il utilise une BDD. Si la premire connexion la base de donne ne se fait pas, on soulve une exception, qui tentera de se connecter la base de donne, ce qui soulvera une exception... On obtient des comportements plutt imprvus, pouvant aller jusqu' la boucle infinie si le script implmente la fonction set_exception_handler. Il est donc trs important d'viter ce genre de scnario. La meilleure mthode pour viter ceci est de bien distinguer les diffrentes classes d'exception dont le script a besoin. En crant ici une classe d'Exception spcifique la base de donnes, on aurait forcement compris que l'on ne peut pas utiliser la base de donnes, vu que l'appel mme de l'exception signifie que la connexion la base de donnes a chou. On utilisera alors un fichier. De mme, on logguera les exceptions souleves lors d'un accs fichier dans la BDD et non dans un fichier.

En ralit, PHP empche ceci. Si il dtecte une exception lance l'intrieur du traitement d'une autre exception (que ce soit avec catch ou set_exception_handler), il stoppe l'xecution et affichera un message d'erreur. Ainsi, le code suivant :

Exception lance dans le code de traitement d'une autre exception
Sélectionnez

<?php
 
class MyException extends Exception
{
    public function __construct($msg=null, $code=0)
    {
        parent::__construct($msg, $code);
    }
 
    // 3 ) La fonction addLog va essayer de se connecter  MySQL, or cette fonction est 
    //  justement appele car une prcdente tentative de connexion a choue.
    public function addLog()
    {
        // La tentative choue encore
        if ( ! @mysql_connect($server, $user, $pass) )
        {
            // 4) On lance une exception non capture (on pourait la capturer, 
            //  l'erreur serait identique)
            throw new MyException('Impossible de se connecter  MySQL dans la classe MyException');
        }
    }
}
 
// 5 ) On attrape l'exception lance dans la mthode addLog 
//      et on ressaie d'insrer un log...
//    On voit ici la boucle infinie qui se cre entre l'appel de 
//      cette fonction exception_handler et la mthode addLog.
function exception_handler($myException)
{
    $myException->addLog();
}
 
set_exception_handler('exception_handler');
 
// 1) Le commencement, on ouvre une connexion  MySQL, 
        qui bien sr ne va pas fonctionner
try
{
    if ( ! @mysql_connect($server, $user, $pass) )
    {
        // On lance donc l'exception
        throw new MyException('Impossible de se connecter  Mysql dans le script');
    }
}
// 2) On capture l'exception et on applique le traitement, 
//      c'est  dire insrer un log
catch(MyException $e)
{
    $e->addLog();
}
 
 
?>

Affichera l'erreur suivante.

Erreur gnre
Sélectionnez

Fatal error: Exception thrown without a stack frame in Unknown on line 0

Pour rsumer : il faut bien tre conscient de la cause d'une exception, de faon ne pas appeler de nouveau dans son traitement la portion de code responsable de sa leve. Le mieux est d'tablir une hirarchie des classes d'exception. Par exemple, si on lance une exception dans le script, le traitement pourra tenter d'crire dans la base de donnes, s'il n'y parvient pas, il lance une exception qui tentera d'crire dans un fichier. Si ce traitement est aussi un chec, une nouvelle exception tentera simplement d'afficher l'ecran, si rien ne fonctionne, on lance une erreur simple, ou on ne fait rien du tout. Le meilleur moyen d'viter cette erreur consiste limiter les oprations risque dans le code de traitement des exceptions.


prcdentsommairesuivant

Copyright © 13/09/2006 Guillaume Affringue. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.