我想用一种更干净的方式来获得以下功能,在一个块中捕获AError和BError:

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

有什么办法可以做到吗?还是我得分别抓他们?

AError和Berror有一个共享的基类,但它们还与我希望落入handler2的其他类型共享这个基类,因此不能只捕获基类。


当前回答

更新:

从PHP 7.1开始,这是可用的。

语法为:

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

文档:https://www.php.net/manual/en/language.exceptions.php的例子- 334

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

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


对于7.1之前的PHP:

不管其他答案怎么说,您都可以在同一个块中捕获AError和BError(如果您是定义异常的人,那么就更容易一些)。即使您希望“落空”一些例外情况,您仍然应该能够定义一个层次结构来匹配您的需求。

abstract class MyExceptions extends Exception {}

abstract class LetterError extends MyExceptions {}

class AError extends LetterError {}

class BError extends LetterError {}

然后:

catch(LetterError $e){
    //voodoo
}

正如您在这里和这里看到的,即使是SPL默认异常也有一个可以利用的层次结构。此外,正如PHP手册中所述:

当抛出异常时,语句后面的代码将不会被触发 执行时,PHP将尝试找到第一个匹配的catch块。

这意味着你也可以

class CError extends LetterError {}

你需要处理的不同于AError或error,所以你的catch语句看起来像这样:

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

如果有20个或更多的异常属于同一个超类,并且您需要以一种方式处理其中的5个(或任何较大的组),而其余的则以另一种方式处理,您仍然可以这样做。

interface Group1 {}

class AError extends LetterError implements Group1 {}

class BError extends LetterError implements Group1 {}

然后:

catch (Group1 $e) {}

当涉及到异常时使用OOP是非常强大的。使用像get_class或instanceof这样的东西是hack,如果可能的话应该避免。

我想添加的另一个解决方案是将异常处理功能放在它自己的方法中。

你可以

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

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

假设绝对没有办法控制异常类层次结构或接口(而且几乎总是会有一种方法),您可以执行以下操作:

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

通过这种方式,如果您的异常处理机制需要更改,您仍然只有一个必须修改的代码位置,并且您是在OOP的一般结构中工作。

其他回答

作为可接受答案的扩展,您可以切换Exception的类型,从而产生类似于原始示例的模式:

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;

    }

}

一个很好的方法是使用set_exception_handler。

警告! !在PHP 7中,如果出现致命错误,可能会出现死机白屏。例如,如果你在一个非对象上调用一个方法,你通常会得到致命错误:在null上调用成员函数your_method(),如果错误报告是打开的,你会期望看到这个。

上面的错误不会被catch捕获(异常$e)。 上述错误不会触发set_error_handler设置的任何自定义错误处理程序。

你必须使用catch(Error $e){}来捕获PHP7中的错误。 这可能会有所帮助:

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

PHP 7.1提供了捕获多种类型的能力。

所以:

<?php
try {
    /* ... */
} catch (FirstException $ex) {
    $this->manageException($ex);
} catch (SecondException $ex) {
    $this->manageException($ex);
}
?>

and

<?php
try {

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

在功能上是等同的。

在PHP >= 7.1中,这是可能的。请看这个答案。


如果可以修改异常,请使用此答案。

如果不能,可以尝试用Exception捕获所有异常,然后用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;
    }
}

但是,如前面提到的答案所述,使用多个捕获块可能会更好。

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

更新:

从PHP 7.1开始,这是可用的。

语法为:

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

文档:https://www.php.net/manual/en/language.exceptions.php的例子- 334

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

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


对于7.1之前的PHP:

不管其他答案怎么说,您都可以在同一个块中捕获AError和BError(如果您是定义异常的人,那么就更容易一些)。即使您希望“落空”一些例外情况,您仍然应该能够定义一个层次结构来匹配您的需求。

abstract class MyExceptions extends Exception {}

abstract class LetterError extends MyExceptions {}

class AError extends LetterError {}

class BError extends LetterError {}

然后:

catch(LetterError $e){
    //voodoo
}

正如您在这里和这里看到的,即使是SPL默认异常也有一个可以利用的层次结构。此外,正如PHP手册中所述:

当抛出异常时,语句后面的代码将不会被触发 执行时,PHP将尝试找到第一个匹配的catch块。

这意味着你也可以

class CError extends LetterError {}

你需要处理的不同于AError或error,所以你的catch语句看起来像这样:

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

如果有20个或更多的异常属于同一个超类,并且您需要以一种方式处理其中的5个(或任何较大的组),而其余的则以另一种方式处理,您仍然可以这样做。

interface Group1 {}

class AError extends LetterError implements Group1 {}

class BError extends LetterError implements Group1 {}

然后:

catch (Group1 $e) {}

当涉及到异常时使用OOP是非常强大的。使用像get_class或instanceof这样的东西是hack,如果可能的话应该避免。

我想添加的另一个解决方案是将异常处理功能放在它自己的方法中。

你可以

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

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

假设绝对没有办法控制异常类层次结构或接口(而且几乎总是会有一种方法),您可以执行以下操作:

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

通过这种方式,如果您的异常处理机制需要更改,您仍然只有一个必须修改的代码位置,并且您是在OOP的一般结构中工作。