JeuWeb - Crée ton jeu par navigateur
[Résolu]de bonnes pratiques pour la gestion des exceptions ? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [Résolu]de bonnes pratiques pour la gestion des exceptions ? (/showthread.php?tid=4617)

Pages : 1 2


[Résolu]de bonnes pratiques pour la gestion des exceptions ? - Ter Rowan - 04-03-2010

Coucou

Chers amis, j'ai du mal avec les exceptions.

Autant je sais appliquer les exceptions (try catch et compagnie) autant je n'arrive pas à mesurer l'intérêt de ce système (par rapport à un if tout bête)

Aussi je me demandais, après quelques recherches infructueuses sur le net (mais bon google est pas trop mon pote) si vous n'aviez pas un site, une documentation, etc... à la fois théorique et concrète (exemple, si possible php, je suis tombé sur des trucs en java, mais j'ai l'impression que java diffère de php sur ce point) d'une bonne utilisation des exceptions.

Encore une fois je sais faire (dans mon bouquin php,il y a un article de 5 lignes traitant les exceptions mais il ne fait que m'expliquer comment créer une exception de division par 0 dans une fonction de division...)

mais je crains de mal comprendre l'intérêt, puisque je ne vois pas de différence avec les if (dans l'exemple, il suffit de faire if $d===0 erreur('division par 0'); )


RE: de bonnes pratiques pour la gestion des exceptions ? - Joojo - 04-03-2010

Je ne pourrai pas t'aider car je n'en suis pas encore là dans l'apprentissage de la POO mais je connais un tutorial d'un membre du sdz qui traite ce sujet, si tu ne l'as pas encore vu:

http://www.siteduzero.com/tutoriel-3-172329-les-exceptions.html


RE: de bonnes pratiques pour la gestion des exceptions ? - Ter Rowan - 04-03-2010

merci Smile mais justement j'en suis à ce niveau là et ça me frustre parce que, finallement ça explique le comment faire, pas le pour quoi faire (pour quoi en deux mots)


RE: de bonnes pratiques pour la gestion des exceptions ? - Sephi-Chan - 04-03-2010

L'avantage de l'exception, c'est que le langage gère sa propagation. Ton application remarque un comportement exceptionnel, tu lèves ton exception et tu peux la gérer au niveau que tu veux, pas forcément dans le fragment où l'erreur survient.

Exemple.

Admettons que j'ai un contrôleur UsersController, une action effectue un appel à une méthode de mon modèle User, qui elle-même fait un appel au modèle Planet (par exemple Planet.find(given_id)). Le comportement de find, quand on lui donne un entier, c'est de chercher la ligne qui a cet entier pour id et de jeter une exception ActiveRecord::RecordNotFound s'il ne trouve rien.

Ici, je peux gérer l'exception dans le modèle Planet, dans le modèle User, dans le contrôleur UsersController ou dans son parent ApplicationController (tous les contrôleurs en héritent).

J'ai donc un niveau de souplesse exceptionnel (sans jeu de mot) !


Sephi-Chan


RE: de bonnes pratiques pour la gestion des exceptions ? - QuentinC - 04-03-2010

Concernant la différence entre java et php au sujet des exceptions, la plus marquante est à mon avis qu'en java, tu es généralement obligé de catcher, le langage te l'impose. En php, tu fais ce que tu veux.

Le grand avantage des exceptions c'est que tu peux gérer le problème de différentes façons et à différents niveaux selon ce que tu veux faire. Pour reprendre l'exemple de Séphi-Chan, si tu rencontres une exception comme quoi une planète n'existe pas, alors dans un certain cas tu peux décider d'afficher une erreur à l'utilisateur, et dans un autre tu peux décider de rattraper ce problème en créant une nouvelle planète. Tu me diras, tu peux aussi faire ça avec des if. Le problème des if c'est que tu es obligé de les répéter à chaque fois que tu veux ravoir le même comportement. Avec les exceptions, tu as une occasion supplémentaire de regrouper les cas et n'écrire qu'une fois le code.

Admettons que nous avons un code comme celui-ci pour effectuer une série de requêtes dans la base de données. C'est classique...
Code :
commencer une transaction
résultat1 = exécuter requête1
si résultat1 = erreur alors rollback
sinon {
résultat2 = exécuter requête2
si résultat2 = erreur alors rollback
sinon {
résultat3 = exécuter requête3
si résultat3 = erreur alors rollback
sinon {
traiter résultat1
traiter résultat2
traiter résultat3
commit
} // fin si 3
} // fin si 2
} // fin si 1

Que se passe-t-il le jour où il faut changer de comportement en cas d'erreur ? Si à la place de rollback on doit arrêter un réacteur nucléaire ? Eh bien, il faut faire la modification trois fois. ET puis cette structure en conditions imbriquées n'est pas très pratique.

Si on utilise les exceptions, le code est tout de suite plus simple, plus clair et surtout, il n'y a qu'un seul bout de code à changer si on veut remplacer notre rollback par l'arrêt du réacteur nucléaire.:
Code :
essayer  {
commencer une transaction
résultat1 = exécuter requête1
résultat2 = exécuter requête2
résultat3 = exécuter requête3
traiter résultat1
traiter résultat2
traiter résultat3
commit
} rattraper (exception de requête) {
rollback
}

Je sais pas si mes explications sont claires et si elles t'ont aidées...


RE: de bonnes pratiques pour la gestion des exceptions ? - Ter Rowan - 05-03-2010

merci à tous les deux

peut être que je me fais un monde de cela mais j'ai l'impression qu'il y a un truc bcp plus puissant que cela derrière les exceptions, mais bon je dois délirer

autant les patterns type factory et stragey , quand j'ai découvert, et donc compris, ce qu'il faisait, j'ai trouvé ça super puissant, autant les exceptions, je trouve que c'est "juste un peu mieux". J'ai donc l'impression que quelquechose m'échappe, mais peut être pas finalement ... ^^


plus qu'à refaire mes portions de codes où j'ai placé des if...


Mais sinon... Vous faites beaucoup de classe héritant d'exception ou juste une ou deux génériques ?


RE: de bonnes pratiques pour la gestion des exceptions ? - Sephi-Chan - 05-03-2010

Les exceptions sont juste un moyen technique de gérer les erreurs inattendues.

Ils ne doivent pas nécessaire remplacer les tests conditionnels : comme leur nom l'indique, c'est pour gérer les événements exceptionnelles. Et ça permet à ton application d'arriver à se remettre sur pied toute seule quand une telle erreur se produit.

Un petit exemple (en Ruby…) :


begin
@planet = @user.planets.find(planet_id) # Lance une ActiveRecord::RecordNotFound si aucune planète n'est trouvée.
@planet.do_something_on_the_planet # On serait comme des cons sans planète !

rescue ActiveRecord::RecordNotFound
@user.planets.create :name => Planet.generate_planet_name
retry # Try again, noob ! Recommence le bloc depuis begin. Ça n'existe pas en PHP.

else
# Si c'est un autre type d'exception, on fait autre chose…

ensure
# C'est l'équivalent du finally du Java.
# Ce qui est là sera toujours effectué, exception ou non.
# C'est donc très pratique pour fermer un flux, une connexion, etc.
# Hélas, ça n'existe pas en PHP non plus…

end

Toujours persuadé que ça manque de puissance ? Confusediffle:

Après, c'est sûr qu'en PHP, tu perds un peu d'intérêt avec son support limité, mais bon…
Ça reste super pratique pour faire des programmes robustes !


En ce qui me concerne, je crée une extension par type d'erreur exceptionnelle. Au final il n'y en a pas des masses : j'en ai une dizaine sur un petit jeu.

Je t'encourage à jeter un œil (NotThrowablePieceOfBodyError !) à l'article Système de gestion d'exceptions. Il explique bien les enjeux d'un tel système.

Dans le cas de nos jeux, il y a un argument qui me plaît bien :

Wikipedia a écrit :Dans les langages de programmation sans SGE, on n'a pas d'outil pour séparer l'exécution normale et l'exécution exceptionnelle du programme. Un algorithme, dont l'exécution normale s'exprime de façon simple et élégante, peut devenir illisible (et donc difficile à maintenir) une fois « enrobé » par une logique de traitement des situations exceptionnelles ; disposer au niveau du langage de programmation d'une syntaxe pour différencier l'exécution normale de l'exécution dans un contexte exceptionnel peut être utile.


Sephi-Chan


RE: de bonnes pratiques pour la gestion des exceptions ? - barst - 05-03-2010

En fait, le PHP reprend les exceptions comme un acquis de la POO.
Tu dois plutôt chercher à comprendre ce que signifie une exception en POO plutôt qu'en PHP.
Il faut donc la voir dans une utilisation industrielle/professionnelle.

Tout d'abord, une exception se propage de l'objet appellé à l'objet appellant en remontant la chaîne d'appellant jusqu'à être interceptée par un catch.
Ce qui oblige à prendre en compte les exceptions, et donc les erreurs, dans un domaine professionnel sinon ton programme s'arrête.
Une fonction qui retourne une erreur peut être ignorée, vous mêmes est-ce que vous testez systématiquement le retour des fonctions PHP ?

Avec les exceptions, il y a à la fin l'arrêt de l'exécution si elle n'est pas prise en compte, ceci afin d'éviter d'endommager les données.

Maintenant, le catch permet d'intercepter l'exception, et d'éviter l'arrêt brutal, mais il permet aussi d'apporter un traitement personnalisé en fonction de l'exception.

Toujours dans un domaine industriel, nous avons un programme qui gère des lots séquentiellement, un des éléments du lot est considéré comme erroné et une exception est levée.
Selon la non-conformité de l'élement on peut décider si on continue à traiter le lot en cours mais en rejetant seulement l'élément, ou alors rejeter tous le lot et passer au lot suivant.
Si jamais on tombe sur une non-conformité totalement inconnue, alors on peut ne pas attraper l'exception qui arrêtera la chaîne de traitement et obligera un utilisateur humain à venir constater


Donc pour résumé, par rapport à des tests standard et les codes erreurs, l'exception :
- met fin au traitement actuel en cours,
- peut permettre la reprise du traitement si le catch le permet
- met fin totalement au traitement si elle n'est pas prise en compte


RE: de bonnes pratiques pour la gestion des exceptions ? - Ter Rowan - 05-03-2010

bah je suis démoralisé

repas avec mes gars ce midi, je parle de mon sujet d'exception, de la manière dont aujourd'hui je traite mes erreurs, etc...

conclusion : "c'est de la merde" ce que je fais

alors on va s'y mettre...


merci en tout cas pour vos éclaircissements
Je pense que je vais y revenir car autant je suis sur la bonne pente pour me persuader d'essayer le catch (oulala le joke) autant je ne suis pas convaincu de le faire correctement :p


RE: de bonnes pratiques pour la gestion des exceptions ? - Ter Rowan - 05-03-2010

[EDIT DE TER ROWAN] ce qui est en dessous, est finalement... n'importe quoi enfin je trouve ^^ [/EDIT]

alors voila ma première analyse, ce serait bien sympa de me dire ce que vous pensez de mon idée : :respect:

Sachant que je souhaite avoir une gestion centralisée de tous les messages (potentiellement avec message multilingue, etc...)
Sachant que j'ai deux cas de figure : (1) des pages appelées (2) des script qui renvoient de l'XML (appel ajax)


Si je suis sur une page appelée, je cherche à générer par un gestionnaire central une page "spécifique" d'erreur, intelligible par l'internaute

Page appelée :

mapage.php
Code PHP :
<?php 
// j'instancie le gestionnaire d'erreur (singleton)
$gestionnaire = classGestionnaireErreur::getInstance();
$gestionnaire->setContexte('page');
try
// première instruction de mapage.php après l'instanciation
{
/*
puis tout le code
*/
}
catch(
Exception $e)
{
$gestionnaire->echo(); // génération du message à destination de l'internaute
}

Si je suis sur un retour XML, j'envoie un message d'erreur via une balise d'erreur générée par le meme "echo" de mon gestionnaire d'erreur, qui sera interprété côté client (javascript, ou flash, ou je sais pas quoi)

monscript.php
Code PHP :
<?php 
// j'instancie le gestionnaire d'erreur (singleton)
$gestionnaire = classGestionnaireErreur::getInstance();
$gestionnaire->setContexte('xml');
try
// première instruction de monscript.php après l'instanciation
{
/*
puis tout le code
*/
}
catch(
Exception $e)
{
$gestionnaire->echo();
}

l'idée dans monscript.php comme dans mapage.php est de me garantir que rien ne sera envoyé sur le poste client a part l'echo du gestionnaire. En même temps que j'écris je me dis que ca ne va pas fonctionner comme cela... Du coup, comment faire pour "effacer tout ce qui aurait pu être envoyé avant (supposons des buffers vidés, etc.. )?


maintenant, quelque soit l'endroit où je me trouve dans le code, je vais me trouver avec des bloc try catch du type
Code PHP :
<?php 
try
{
/* mon bloc homogène */
}
catch(
Exception $e)
{
/* dans les cas où je veux écrire un nouveau message */
$gestionnaire = classGestionnaireErreur::getInstance();
$gestionnaire->setErreur( 32 ); // 32 le numero d'erreur de ce bloc, ça pourrait être 33 34...

/* dans tous les cas, propagation de l'exception jusqu'au catch de mapage.php ou monscript.php (cf au dessus)*/
throw $e;
}
l'idée étant d'attrapper l'exception avec, si cela est pertinant, la génération d'un message d'erreur. Dans tous les cas, pour que le bloc appelant sache qu'il y a eu une exception, je relance un throw. Mais peut être que là aussi je me plante ?

pas simple, je n'ai pas cette culture, et là je me sens à poil complet :pleure2: