Home  >  Q&A  >  body text

Combine multiple exception types in a catch block

I would like a cleaner way to get 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 capture them individually?

AError and Berror have a shared base class, but they are also shared with other types that I want to fall into handler2, so I can't just capture the base kind.

P粉547420474P粉547420474339 days ago540

reply all(2)I'll reply

  • P粉777458787

    P粉7774587872023-10-15 15:07:15

    This is possible in PHP >= 7.1. See this answer.


    If you can modify the exception, please use this answer .

    If not, you can try to catch all exceptions using Exception and then use 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 is better to use multiple catch blocks as mentioned in the answer above .

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

    reply
    0
  • P粉611456309

    P粉6114563092023-10-15 00:46:51

    renew:

    This feature is available starting with PHP 7.1.

    The syntax is:

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

    Documentation: https://www.php.net/manual/en/language.exceptions.php#example-334

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

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


    For versions prior to PHP 7.1:

    Despite what these other answers say, you can catch both AError and BError in the same block (it's easier if you're the one defining the exception). Even if there are exceptions that you wish to "exclude", you should still be able to define the hierarchy to suit 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 exception has a hierarchy that can be exploited. Additionally, as stated in the PHP Manual:

    This means you can also have

    class CError extends LetterError {}

    You need to handle it differently than AError or BError, so your catch statement will look like this:

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

    If you have a situation where there are twenty or more exceptions that legitimately belong to the same superclass, and you need to handle five of them (or any large group) in one way, and the rest in Another way to handle it, you can still do it.

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

    Then:

    catch (Group1 $e) {}

    Using OOP is very powerful when handling exceptions. Using things like get_class or instanceof is a hack and should be avoided if possible.

    Another solution I'd like to add is to put the exception handling functionality into its own method.

    You can have

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

    Assuming that you have absolutely no way to control the exception class hierarchy or interface (and almost always there 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);
    }

    This way, if your exception handling mechanism needs to change, you still only have one code location that must be modified, and you are working within the general construct of OOP.

    reply
    0
  • Cancelreply