Catching multiple exception types in one catch block

匿名 (未验证) 提交于 2019-12-03 08:59:04

问题:

I'd like a cleaner way to obtain the following functionality, to catch AError and BError in one block:

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

Is there any way to do this? Or do I have to catch them separately?

AError and Berror have a shared base class, but they also share it with other types that I'd like to fall through to handler2, so I can't just catch the base class.

回答1:

If you can modify the exceptions, use this answer.

If you can't, you could try catching all with Exception and then check which exception was thrown with 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;     } } 

But it would probably be better to use multiple catch blocks as described in aforementioned answer.

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


回答2:

Despite what these other answers say, you can catch AError and BError in the same block (it is somewhat easier if you are the one defining the exceptions). Even given that there are exceptions you want to "fall through", you should still be able to define a hierarchy to match your needs.

abstract class MyExceptions extends \Exception {}  abstract class LetterError extends MyExceptions {}  class AError extends LetterError {}  class BError extends LetterError {} 

Then:

catch(LetterError $e){     //voodoo } 

As you can see here and here, even the SPL default exceptions have a hierarchy you can leverage. Additionally, as stated in the PHP Manual:

When an exception is thrown, code following the statement will not be executed, and PHP will attempt to find the first matching catch block.

This means you could also have

class CError extends LetterError {} 

which you need to handle differently than AError or BError, so your catch statement would look like this:

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

If you had the case where there were twenty or more exceptions that legitimately belonged under the same superclass, and you needed to handle five (or whatever large-ish group) of them one way and the rest the other, you can STILL do this.

interface Group1 {}  class AError extends LetterError implements Group1 {}  class BError extends LetterError implements Group1 {} 

And then:

catch (Group1 $e) {} 

Using OOP when it comes to exceptions is very powerful. Using things like get_class or instanceof are hacks, and should be avoided if possible.

Another solution I would like to add is putting the exception handling functionality in its own method.

You could have

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

Assuming there is absolutely no way you can control exception class hierarchies or interfaces (and there almost always will be a way), you can do the following:

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); } 

In this way, you are still have a only single code location you have to modify if your exception handling mechanism needs to change, and you are working within the general constructs of OOP.



回答3:

Coming in PHP 7.1 is the ability to catch multiple types.

So that this:

manageException($ex); } catch (SecondException $ex) {     $this->manageException($ex); } ?> 

and

manageException($ex); } ?> 

are functionally equivalent.



回答4:

As of PHP 7.1,

catch( AError | BError $e ) {     handler1( $e ) } 

interestingly, you can also:

catch( AError | BError $e ) {     handler1( $e ) } catch (CError $e){     handler2($e); } catch(Exception $e){     handler3($e); } 

and in earlier versions of 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     } } 


回答5:

This article covers the question electrictoolbox.com/php-catch-multiple-exception-types. Content of the post copied directly from the article:

Example exceptions

Here's some example exceptions that have been defined for the purposes of this example:

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   } } 

Handling multiple exceptions

It's very simple - there can be a catch block for each exception type that can be thrown:

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 } 

If an exception is thrown that is not handled by any of the other catch statements it will be handled by the catch(Exception $e) block. It does not necessarily have to be the last one.



回答6:

As an extension to the accepted answer, you could switch the type of Exception resulting in a pattern that is somewhat like the original example:

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:

Here's a reasonable alternative if you don't have control over defining the exceptions. Use the name of the exception variable to categorize the exceptions when they are caught. Then check for the exception variable after the try/catch block.

$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); } 

This somewhat odd looking approach is probably only worth it if there is a lot of duplication between catch block implementations.



回答8:

Besides fall-through, it's also possible to step over by using goto. It's very useful if you want to see the world burn.

3v4l.org



回答9:

A great way is to use set_exception_handler.

Warning!!! with PHP 7, you might get a white screen of death for fatal errors. For example, if you call a method on a non-object you would normally get Fatal error: Call to a member function your_method() on null and you would expect to see this if error reporting is on.

The above error will NOT be caught with catch(Exception $e). The above error will NOT trigger any custom error handler set by set_error_handler.

You must use catch(Error $e){ } to catch errors in PHP7. . This could help:

class ErrorHandler{     public static function excep_handler($e)     {         print_r($e);     } } set_exception_handler(array('ErrorHandler','excep_handler')); 


回答10:

Another option not listed here is to use the code attribute of an exception, so you can do something like this:

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     } } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!