Les exceptions de la SPL

Signaler
Messages postés
16
Date d'inscription
mardi 18 novembre 2003
Statut
Membre
Dernière intervention
23 septembre 2010
-
Messages postés
16
Date d'inscription
mardi 18 novembre 2003
Statut
Membre
Dernière intervention
23 septembre 2010
-
Bonjour à tous,
Je cherche des exemples concrets d'utilisation des exceptions de la spl.
La doc étant vide, ça serait bien de croiser nos expériences et d'expliquer quand tel type d'exception doit être lancé.
Je pense que le sujet peut intéresser beaucoup de monde donc j'attends vos réponses.
Donc à vos claviers

8 réponses

Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
18
Salut,

Un document que je garde précieusement : http://talks.somabo.de/200504_php_quebec_spl_for_the_masses.pdf
Pages 38 à 46.
Ce sont des diapos d'une conférence, donc... il manquerait tout le texte de la conférence. Cela dit, c'est un très bon aide-mémoire et une excellente base de réflexion pour la question que tu te poses.

Comme maintenant je vais être abonné à ce sujet, tu peux en profiter pour poser des questions (après avoir lu le document en lien, hein ;) ).
Et peut-être qu'à l'occasion je ferai un tuto.
Sinon, il existe très probablement des tutos sur le net, mais je ne les connais pas...

--
Neige

Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
Messages postés
16
Date d'inscription
mardi 18 novembre 2003
Statut
Membre
Dernière intervention
23 septembre 2010

Merci d'avoir prit le temps de me répondre.
Très intéressante comme doc. Je dois dire qu'elle est bien faite mais je me pose encore certaines questions.
Par exemple la différence entre RangeException et OutOfRangeException. J'ai du mal à savoir quand utiliser l'une ou l'autre.
Idem pour OutOFBoundsException qui reste peu clair dans mon esprit.

Je vais essayer d'illuster avec un exemple car c'est beaucoup plus parlant qu'un long discours.

class Port
    {
    private
        $_port;
    public function setPort($port = null)
        {
        if(empty($port) || !is_int($port))
            {
            throw new InvalidArgumentException('Le port doit être un entier.');
            }
        elseif($port < 0 || $port > 65535)
            {
            // Là je me dis que OutOfRangeException peut aussi être utilisé car nous sommes en dehors de l'intervalle de validité.
            throw new RangeException('Le port doit être un entier comprit dans la plage 0-65535');
            }
        else
            {
            $this->_port = $port;
            }   
        }


Ou alors OutOfRangeException est utiliser lorsqu'un nombre (par exemple) sort de sa plage de validité. Par exemple si un nombre dépasse la taille maximal d'un entier php. Mais là je me dis que nous sommes dans le cas d'un débordement d'entier et que OverflowException est plus appropriée.

Comme tu le remarques, Je me pose des questions de quand utiliser tel type d'exception plutôt qu'une autre.
C'est dommage que la doc ne soit pas plus fournie. Surtout pour des outils aussi puissants. Qui rendrait php un peu plus structuré et contriburait à faire avancer php vers le monde pro.
Si t'as des exemples je suis preneur
Messages postés
16
Date d'inscription
mardi 18 novembre 2003
Statut
Membre
Dernière intervention
23 septembre 2010

Je vais poster un autre exemple mais utilisant DomainException. Juste pour savoir si j'ai bien comprit son utilisation.

class Email
    {
    private
        $_email;
    public function setEmail($email = null)
        {
        if(empty($email) || !is_string($email))
            {
            throw new InvalidArgumentException('L\'adresse email doit être un chaine de caractères.');
            }
        elseif(!filter_var($email,FILTER_VALIDATE_EMAIL))
            {
            // sort du domaine de validité des email.
            throw new DomainException('L\'adresse email n'est pas valide.');
            }
        else
            {
            $this->_email = $email;
            }
        }
    }
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
18
Salut,

Il semblerait que la différence entre OutOfBoundsException et OutOfRangeException soit franchement ténue.
Cependant la réflexion est intéressante et je me dis, finalement, qu'on doit pouvoir trouver une différence plus flagrante entre les deux... J'avance une hypothèse :
OutOfBoundsException => A utiliser pour un index numérique non valide
OutOfRangeException => A utiliser pour un index alphanumérique non valide
Exemple 1 : on demande un entier entre 1 et 100, l'utilisateur passe 200, qui est en dehors des limites (en dehors de la plage aussi, mais surtout en dehors des limites) => OutOfBoundsException
Exemple 2 : on demande un entier entre 1 et 100, l'utilisateur passe 55,2 => ce n'est pas un entier, InvalidArgumentException
Exemple 3 : on demande une valeur à choisir entre 'a', 'b', 'c', 'd' ou 'e'. L'utilisateur passe 'f', qui est en dehors de la plage (mais on peut difficilement parler de "limite") => OutOfRangeException

Quant à DomainException, je vois des utilisations un peu partout qui ne correspondent PAS DU TOUT à la doc... Beaucoup semblent utiliser cette exception au sens informatique (réseau, internet), le domaine étant alors le Nom de Domaine, voire, plus largement, l'adresse ou quoi que ce soit dans ce genre...
Excemple trouvé allant dans ce sens :
if (!file_exists($file) || !is_writable($file)) {
    throw new \DomainException("File $file invalid");
}

Et là, je m'insurge, parce que la documentation historique dit quelque chose de TOTALEMENT différent... Je cite :
This kind of exception should be used to inform about domain erors in mathematical sense.

Après, pour savoir ce qu'est un domaine de définition d'une fonction, en mathématiques, il suffit de trouve des docs.

La doc est effectivement et malheureusement trop peu fournie sur le sujet... Il existe bien des tutos, mais je ne suis pas sûr que l'on puisse faire confiance aveuglément à tous les auteurs, cf le dernier exemple cité.

En tout cas, ça fait bien plaisir de voir que d'autres se posent ce genre de questions sur les exceptions et tentent de tirer l'utilisation de PHP vers le haut, plutôt que de se contenter de : or die(mysql_errror())

--
Neige

Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
Messages postés
16
Date d'inscription
mardi 18 novembre 2003
Statut
Membre
Dernière intervention
23 septembre 2010

Très intéressant.
Ton hypothèse m'a l'air correcte. Un intervalle pouvant être soit numérique, soit alphabétique soit les deux.

numerique
|------------| OutOfBoundsException

numerique alphabétique
|------------||----------------| OutOfRangeException

Mais pourquoi pas RangeException plutôt que OutOfRangeException?

RangeException
Exception thrown to indicate range errors during program execution.

OutOfRangeException
Exception thrown when an illegal index was requested.


Car dans l'exemple 1 ça fonctionne aussi non? La nuance est mince je trouve.

Par contre pour l'utilisation de DomainException, je n'avais pas vu domain au sens mathématique du mot. Je comprends mieux pourquoi elle hérite de LogicException et non de RuntimeException.

Donc pour le système de fichier c'est plus LogicException

Exception that represents error in the program logic.


Un fichier n'existant pas ou n'étant pas accéssible entrant dans ce cas de figure.
Messages postés
16
Date d'inscription
mardi 18 novembre 2003
Statut
Membre
Dernière intervention
23 septembre 2010

Pour les fichiers, je pense qu'on peu même aller plus loin, si le problème peu être détecté avant l'exécution c'est LogicException sinon c'est RuntimeException.

RuntimeException
Exception thrown for errors that are only detectable at runtime.


LogicException
Exception that represents error in the program logic.


Prenon des exemples :

Exemple 1 : J'ai un fichier test.txt pour x raison celui-ci est effacé durant l'exécution. Plus loin dans le programme, je tente de le lire, celui-ci n'existe pas => RuntimeException

Exemple 2 : J'ai un fichier test.txt accéssible en lecture et pour x raison les droits de celui-ci sont changé durant l'exécution. Plus loin dans le programme, je tente de le lire, celui-ci n'est pas accéssible => RuntimeException

Exemple 3 : Je tente de créer un fichier avec fopen, ou mkdir et celui-ci échoue, c'est une erreur de logic non détectable avant l'exécution donc => LogicException. Idem pour la suppression des fichiers.

Exemple 4 : J'ai un fichier test.txt Je test si celui-ci existe or celui-ci est déplacé pendant l'exécution => LogicException
Exemple 5 : J'ai un fichier test.txt Je test si celui-ci existe or celui-ci n'existait pas avant l'exécution => RuntimeException

C'est juste quelques exemples.
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
18
A priori, OutOfRangeException est à utiliser quand la valeur donnée se trouve en dehors de l'intervalle, RangeException quand un intervalle invalide est donné (et là, je pompe la seule phrase de la doc)

Je crois que tu t'es planté dans ta dernière phrase... Ce serait pas plutôt :
Un fichier n'existant pas ou n'étant pas accéssible entrant dans ce cas de figure.

??
Les exceptions qui héritent de RuntimeException proviennent d'erreurs de l'utilisateur (j'entends par là : l'utilisateur de la classe qui lève l'exception et éventuellement l'utilisateur final). Les exceptions qui héritent de LogicException proviennent "d'erreurs de programmation" et ne devraient pas provoquer d'erreur à l'exécution.
Un fichier inexistant, un email invalide, cela ne peut pas être prévu par le développeur, ce sont bien des RuntimeException.

Ton post suivant arrive à ce moment de la rédaction de ma réponse.
Je pense que tes exemples ne sont pas corrects.
Toutes les erreurs que tu cites en exemple sont des erreurs à l'exécution (RuntimeException), pas des erreurs logiques (LogicException). Il n'est JAMAIS possible pendant la conception de prévoir ce qui va se passer lors de l'écriture/lecture/etc d'un fichier.
Par contre, si on tente de donner de manière programmatique un nom invalide à un fichier et qu'on tente de le créer, alors on aura une erreur logique. Idem si on tente d'accéder à un fichier par un nom variable mal défini.
Exemple : j'ai un fichier /srv/http/default/data/bidule.txt
j'ai $name = 'bidule' défini quelque part. Je tente d'accéder au fichier :
$content = file_get_contents(ROOT.$name.'.txt);
Si j'ai correctement défini ma constante ROOT et que je n'accède pas au fichier, soit il n'existe pas (ou plus), soit je n'ai pas les permissions, soit le nom est erroné => RuntimeException, parce que je ne pouvais pas le deviner quand j'ai écrit mes lignes de code.
Par contre si je me suis complètement planté dans la définition de ma constante ROOT, ou que j'ai déplacé le répertoire parce que je trouve que maintenant l'arborescence de mon site est plus simple, alors c'est une erreur de ma part => LogicException.

Pour pousser le bouchon un peu plus loin, toujours avec le même exemple. Si le fichier n'est plus là parce que je me suis planté dans la manipulation de mes fichiers : s'il s'agit d'un fichier de cache et que mon système de cache est mal implémenté, il va le supprimer car obsolète mais pas le réécrire => LogicException.

Mais une RuntimeException n'est pas véritablement une erreur : c'est une exception, et c'est là toute la différence. C'est à dire que ce n'est pas le fonctionnement "normal" du programme. Une exception, ça peut se gérer très proprement. D'où l'importance d'avoir suffisament d'exceptions étendues pour pouvoir gérer les "erreurs" qui surviennent lors de l'exécution de son programme : plus on découpe, plus on peut gérer de petits morceaux de code susceptibles de causer des erreurs et moins on a de chances d'avoir une bête page d'erreur pour dire à l'utilisateur que non, il ne verra rien, parce que 1,2 n'est pas un entier.

--
Neige

Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
Messages postés
16
Date d'inscription
mardi 18 novembre 2003
Statut
Membre
Dernière intervention
23 septembre 2010

Oui une exception comme son nom l'indique doit être levé lorsqu'il y a quelque chose d'exceptionnel. Sinon c'est une simple erreur.
Elle n'arrête pas forcement l'application. Si une exception est levé, il est possible de tenter de corriger le problème et de reprendre l'exécution sans même que l'utilisateur final ne le voit.
En tout cas je te remercie, la confrontation d'idées m'éclaire un peu plus sur le fonctionnement des exceptions de la spl.