337 votes

Capture de plusieurs types d'exception dans un seul bloc catch

J'aimerais un moyen plus propre d'obtenir la fonctionnalité suivante, pour attraper AError y BError en un seul bloc :

try
{
    /* something */
}
catch( AError, BError $e )
{
    handler1( $e )
}
catch( Exception $e )
{
    handler2( $e )
}

Y a-t-il un moyen de le faire ? Ou dois-je les attraper séparément ?

AError y Berror ont une classe de base commune, mais ils la partagent aussi avec d'autres types que je voudrais faire passer à handler2 donc je ne peux pas simplement attraper la classe de base.

7 votes

Juste pour ajouter ceci en tant que note secondaire : Un RFC a été déposé pour attraper les exceptions multiples. Nous verrons si cette fonctionnalité sera intégrée au langage PHP... wiki.php.net/rfc/multiple-catch

14 votes

Cette fonctionnalité a été implémentée dans PHP 7.1.

0 votes

En PHP 8.0, il existe un moyen encore plus propre : stackoverflow.com/a/64159544/7082164

537voto

MirroredFate Points 2440

Mise à jour :

A partir de PHP 7.1, ceci est disponible.

La syntaxe est la suivante :

try
{
    // Some code...
}
catch(AError | BError $e)
{
    // Handle exceptions
}
catch(Exception $e)
{
    // Handle the general case
}

Docs : https://www.php.net/manual/en/language.exceptions.php#example-294

RFC : https://wiki.php.net/rfc/multiple-catch

Engagez-vous : https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a


Pour PHP avant 7.1 :

Malgré ce que disent ces autres réponses, vous pouvez attraper AError y BError dans le même bloc (c'est un peu plus facile si c'est vous qui définissez les exceptions). Même s'il y a des exceptions que vous voulez "passer à travers", vous devriez être en mesure de définir une hiérarchie correspondant à vos besoins.

abstract class MyExceptions extends Exception {}

abstract class LetterError extends MyExceptions {}

class AError extends LetterError {}

class BError extends LetterError {}

Ensuite :

catch(LetterError $e){
    //voodoo
}

Comme vous pouvez le constater aquí y aquí même le SPL Les exceptions par défaut ont une hiérarchie dont vous pouvez tirer parti. De plus, comme indiqué dans le Manuel PHP :

Lorsqu'une exception est levée, le code suivant la déclaration ne sera pas exécuté, et PHP va essayer de trouver le premier bloc de capture correspondant.

Cela signifie que vous pourriez aussi avoir

class CError extends LetterError {}

que vous devez traiter différemment de AError o BError donc votre déclaration d'intention ressemblerait à ceci :

catch(CError $e){
    //voodoo
}
catch(LetterError $e){
    //voodoo
}

Si vous avez le cas où il y a vingt exceptions ou plus qui appartiennent légitimement à la même superclasse, et que vous avez besoin de traiter cinq (ou n'importe quel groupe plus ou moins important) d'entre elles d'une façon et le reste de l'autre, vous pouvez TOUJOURS le faire.

interface Group1 {}

class AError extends LetterError implements Group1 {}

class BError extends LetterError implements Group1 {}

Et puis :

catch (Group1 $e) {}

L'utilisation de la POO en matière d'exceptions est très puissante. L'utilisation de choses comme get_class o instanceof sont des hacks, et doivent être évités si possible.

Une autre solution que j'aimerais ajouter est de placer la fonctionnalité de traitement des exceptions dans sa propre méthode.

Vous auriez pu

function handleExceptionMethod1(Exception $e)
{
    //voodoo
}

function handleExceptionMethod2(Exception $e)
{
    //voodoo
}

En supposant qu'il n'y a absolument aucun moyen de contrôler les hiérarchies de classes d'exception ou les interfaces (et il y a presque toujours des sera être un moyen), vous pouvez faire ce qui suit :

try
{
    stuff()
}
catch(ExceptionA $e)
{
    $this->handleExceptionMethod1($e);
}
catch(ExceptionB $e)
{
    $this->handleExceptionMethod1($e);
}
catch(ExceptionC $e)
{
    $this->handleExceptionMethod1($e);
}
catch(Exception $e)
{
    $this->handleExceptionMethod2($e);
}

De cette façon, vous n'avez toujours qu'un seul emplacement de code à modifier si votre mécanisme de gestion des exceptions doit changer, et vous travaillez dans le cadre des constructions générales de la POO.

5 votes

Voici un autre vote pour que ce soit la bonne réponse. Malheureusement, des choses comme ce qui est dit dans la réponse acceptée et le fait qu'elle soit acceptée comme la réponse correcte, est ce qui fait de PHP la folie qu'il est.

0 votes

Cela devrait être la réponse acceptée. Bien qu'elle suppose que vous soyez en mesure de modifier les fichiers. AError pourrait être implémenté dans une bibliothèque/un fichier mis à jour par une tierce partie.

0 votes

@WaffleStealer654 Vous pouvez toujours sous-classer les fichiers et les faire implémenter votre groupe, même si vous ne pouvez pas éditer les fichiers directement. Cela supposerait que vous puissiez lancer les exceptions, mais vous pourriez simplement envelopper le mécanisme le plus basique où l'exception serait lancée, puis l'attraper et lancer votre exception enveloppée.

238voto

alex Points 186293

En PHP >= 7.1, c'est possible. Voir ce qui suit respuesta .


Si vous pouvez modifier les exceptions, utiliser cette réponse .

Si vous ne pouvez pas, vous pouvez essayer de tout attraper avec Exception et ensuite vérifier quelle exception a été levée avec instanceof .

try
{
    /* something */
}
catch( Exception $e )
{
    if ($e instanceof AError OR $e instanceof BError) {
       // It's either an A or B exception.
    } else {
        // Keep throwing it.
        throw $e;
    }
}

Mais il serait probablement préférable de utiliser plusieurs blocs de capture comme décrit dans la réponse précédente .

try
{
    /* something */
}
catch( AError $e )
{
   handler1( $e );
}
catch ( BError $b )
{
   handler2( $e );
}

6 votes

C'est ce que je craignais. Les attraper ensemble et tester le type serait bien s'il y avait beaucoup de types d'erreur qui devaient être traités ensemble, mais pour seulement 2, comme dans mon cas, les attraper séparément est probablement plus propre. Merci !

3 votes

@DominicGurto : Ouais, j'irais avec ça aussi :) Je m'inquiéterais davantage de l'attitude de PHP vis-à-vis d'un fichier de type finally déclaration. ;)

7 votes

Mais n'oubliez pas que cela attrape TOUTES les exceptions, donc il devrait y avoir quelque chose comme ... } else { throw($e); } s'il ne correspond pas aux deux. Désolé pour la mauvaise syntaxe, je n'ai pas vu php depuis un moment.

29voto

user1983902 Points 164

Cet article traite de la question electrictoolbox.com/php-catch-multiple-exception-types . Contenu du post copié directement de l'article :

Exemples d'exceptions

Voici quelques exemples d'exceptions qui ont été définies pour les besoins de cet exemple :

class FooException extends Exception 
{
  public function __construct($message = null, $code = 0) 
  {
    // do something
  }
}

class BarException extends Exception 
{
  public function __construct($message = null, $code = 0) 
  {
    // do something
  }
}

class BazException extends Exception 
{
  public function __construct($message = null, $code = 0) 
  {
    // do something
  }
}

Traitement des exceptions multiples

C'est très simple : il peut y avoir un bloc catch pour chaque type d'exception qui peut être levée :

try 
{
  // some code that might trigger a Foo/Bar/Baz/Exception
}

catch(FooException $e) 
{
  // we caught a foo exception
}

catch(BarException $e) 
{
  // we caught a bar exception
}

catch(BazException $e) 
{
  // we caught a baz exception
}

catch(Exception $e) 
{
  // we caught a normal exception
  // or an exception that wasn't handled by any of the above
}

Si une exception est levée et qu'elle n'est pas traitée par l'une des autres instructions catch, elle sera traitée par le bloc catch(Exception $e). Il ne doit pas nécessairement s'agir du dernier bloc.

3 votes

Le problème de cette méthode se pose lorsque vous devez exécuter le même code pour deux ou plusieurs exceptions différentes.

0 votes

Ceci a été récupéré de Boîte à outils électrique . Modification du message pour donner le crédit.

0 votes

Avec PHP 7.x, vous devez catch (Throwable $e) pour attraper toutes les exceptions. Voir aussi : php.net/manual/fr/class.throwable.php

23voto

smix96 Points 366

Dans le prolongement de la réponse acceptée, vous pouvez changer le type d'exception, ce qui donne un modèle qui ressemble un peu à l'exemple original :

try {

    // Try something

} catch (Exception $e) {

    switch (get_class($e)) {

        case 'AError':
        case 'BError':
            // Handle A or B
            break;

        case 'CError':
            // Handle C
            break;

        case default:
            // Rethrow the Exception
            throw $e;

    }

}

7 votes

Utiliser des prises multiples au lieu de cette solution.

6voto

dellsala Points 437

Voici une alternative raisonnable si vous n'avez pas le contrôle de la définition des exceptions. Utilisez le nom de la variable d'exception pour catégoriser les exceptions lorsqu'elles sont capturées. Vérifiez ensuite la variable d'exception après le bloc try/catch.

$ABError = null;
try {
    // something
} catch (AError $ABError) {  // let the exception fall through
} catch (BError $ABError) {  // let the exception fall through
} catch (Exception $e) {
    handler2($e);
}
if ($ABError) {
    handler1($ABError);
}

Cette approche quelque peu étrange ne vaut probablement la peine que s'il y a beaucoup de duplications entre les implémentations de blocs de capture.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X