Je voudrais un moyen plus propre d'obtenir les fonctionnalités suivantes, pour attraper AError
et BError
dans un bloc:
try
{
/* something */
}
catch( AError, BError $e )
{
handler1( $e )
}
catch( Exception $e )
{
handler2( $e )
}
Est-ce qu'il y a un moyen de faire ça? Ou dois-je les attraper séparément?
AError
et Berror
ont une classe de base partagée, mais ils la partagent également avec d'autres types que je voudrais utiliser pour passer à handler2
, je ne peux donc pas simplement attraper la classe de base. .
À partir de PHP 7.1, cette option est disponible.
La syntaxe est la suivante:
try
{
// Some code...
}
catch(AError | BError $e)
{
// Handle exceptions
}
catch(Exception $e)
{
// Handle the general case
}
https://wiki.php.net/rfc/multiple-catch
https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a
Malgré ce que disent ces autres réponses, vous pouvez attraper AError
et BError
dans le même bloc (c'est un peu plus facile si vous définissez les exceptions). Même s'il y a des exceptions que vous voulez "passer à travers", vous devriez toujours pouvoir définir une hiérarchie pour répondre à 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 voir ici et ici , même les exceptions par défaut SPL
ont une hiérarchie que vous pouvez exploiter. De plus, comme indiqué dans le Manuel PHP :
Quand une exception est levée, le code suivant l'instruction ne sera pas exécuté et PHP tentera de trouver le premier bloc catch correspondant.
Cela signifie que vous pourriez aussi avoir
class CError extends LetterError {}
que vous devez gérer différemment de AError
ou BError
, de sorte que votre déclaration catch ressemble à ceci:
catch(CError $e){
//voodoo
}
catch(LetterError $e){
//voodoo
}
Si vous aviez le cas où il y avait une vingtaine d'exceptions ou plus qui appartenaient légitimement à la même superclasse et que vous deviez en gérer cinq (ou un groupe quelconque) dans un sens et le reste dans l'autre, vous pouvez TOUJOURS le faire.
interface Group1 {}
class AError extends LetterError implements Group1 {}
class BError extends LetterError implements Group1 {}
Puis:
catch (Group1 $e) {}
Utiliser OOP pour les exceptions est très puissant. Utiliser des choses comme get_class
ou instanceof
sont des hacks, et devraient être évités si possible.
Une autre solution que je voudrais ajouter est de placer la fonctionnalité de gestion des exceptions dans sa propre méthode.
Tu aurais 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'exceptions ou les interfaces (et qu'il y a presque toujours un moyen), vous pouvez procéder comme 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 manière, vous ne disposez toujours que d'un seul emplacement de code que vous devez modifier si votre mécanisme de gestion des exceptions doit être modifié, et vous travaillez dans les structures générales de la programmation orientée objet.
En PHP> = 7.1 c'est possible. Voir le réponse ci-dessous.
Si vous pouvez modifier les exceptions, tilisez cette réponse .
Si vous ne le pouvez pas, vous pouvez essayer de tout attraper avec Exception
, puis 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 tilisez plusieurs blocs catch comme décrit dans la réponse ci-dessus .
try
{
/* something */
}
catch( AError $e )
{
handler1( $e );
}
catch ( BError $b )
{
handler2( $e );
}
À venir PHP 7.1 est la possibilité d’attraper plusieurs types.
Alors que ça:
<?php
try {
/* ... */
} catch (FirstException $ex) {
$this->manageException($ex);
} catch (SecondException $ex) {
$this->manageException($ex);
}
?>
et
<?php
try {
} catch (FirstException | SecondException $ex) {
$this->manageException($ex);
}
?>
sont fonctionnellement équivalents.
À partir de PHP 7.1,
catch( AError | BError $e )
{
handler1( $e )
}
curieusement, vous pouvez aussi:
catch( AError | BError $e )
{
handler1( $e )
} catch (CError $e){
handler2($e);
} catch(Exception $e){
handler3($e);
}
et dans les versions précédentes de PHP:
catch(Exception $ex){
if($ex instanceof AError){
//handle a AError
} elseif($ex instanceof BError){
//handle a BError
} else {
throw $ex;//an unknown exception occured, throw it further
}
}
Cet article couvre la question electrictoolbox.com/php-catch-multiple-exception-types . Contenu de l'article copié directement de l'article:
Exemples d'exceptions
Voici quelques exemples d'exceptions définies aux fins 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
}
}
Gestion de plusieurs exceptions
C'est très simple - il peut y avoir un bloc catch pour chaque type d'exception pouvant être levé:
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 générée qui n'est pas gérée par l'une des autres instructions catch, elle le sera par le bloc catch (Exception $ e). Ce n'est pas nécessairement le dernier.
En tant qu'extension de la réponse acceptée, vous pouvez changer de type d'exception, ce qui donne un motif qui ressemble à celui de l'exemple d'origine:
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;
}
}
Voici une alternative raisonnable si vous n'avez pas le contrôle sur la définition des exceptions. Utilisez le nom de la variable d'exception pour classer les exceptions lorsqu'elles sont interceptées. Ensuite, recherchez 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 n’en vaut probablement la peine que s’il ya beaucoup de duplication entre les implémentations de bloc de capture.
En plus des retombées, il est également possible d’intervenir en utilisant goto . C'est très utile si vous voulez voir le monde brûler.
<?php
class A_Error extends Exception {}
class B_Error extends Exception {}
class C_Error extends Exception {}
try {
throw new A_Error();
}
catch (A_Error $e) { goto abc; }
catch (B_Error $e) { goto abc; }
catch (C_Error $e) {
abc:
var_dump(get_class($e));
echo "Gotta Catch 'Em All\n";
}
Un bon moyen consiste à utiliser set_exception_handler
.
Attention!!! avec PHP 7, vous pourriez obtenir un écran blanc de la mort pour les erreurs fatales. Par exemple, si vous appelez une méthode sur un non-objet, vous obtiendrez normalement Fatal error: Call to a member function your_method() on null
et vous vous attendez à le voir si le rapport d'erreur est activé.
L'erreur ci-dessus ne sera PAS interceptée avec catch(Exception $e)
. L'erreur ci-dessus NE déclenchera PAS un gestionnaire d'erreurs personnalisé défini par set_error_handler
.
Vous devez utiliser catch(Error $e){ }
pour intercepter les erreurs en PHP7. . Cela pourrait aider:
class ErrorHandler{
public static function excep_handler($e)
{
print_r($e);
}
}
set_exception_handler(array('ErrorHandler','excep_handler'));
Une autre option non répertoriée ici consiste à utiliser l'attribut code
d'une exception afin de pouvoir effectuer quelque chose comme ceci:
try {
if (1 === $foo) {
throw new Exception(sprintf('Invalid foo: %s', serialize($foo)), 1);
}
if (2 === $bar) {
throw new Exception(sprintf('Invalid bar: %s', serialize($foo)), 2);
}
} catch (Exception $e) {
switch ($e->getCode()) {
case 1:
// Special handling for case 1
break;
case 2:
// Special handling for case 2
break;
default:
// Special handling for all other cases
}
}
Hmm, il existe de nombreuses solutions écrites pour les versions php inférieures à 7.1.
Voici un autre simple pour ceux qui ne veulent pas intercepter toutes les exceptions et ne peuvent pas créer d'interfaces communes:
<?php
$ex = NULL
try {
/* ... */
} catch (FirstException $ex) {
// just do nothing here
} catch (SecondException $ex) {
// just do nothing here
}
if ($ex !== NULL) {
// handle those exceptions here!
}
?>