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

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

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

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


当前回答

从PHP 8.0开始,当您不需要输出错误内容(从变量$e)时,您可以使用更清晰的方式来捕获异常。但是你必须用Throwable替换默认的Exception。

try {
    /* something */
} catch (AError | BError) {
    handler1()
} catch (Throwable) {
    handler2()
}

其他回答

从PHP 8.0开始,当您不需要输出错误内容(从变量$e)时,您可以使用更清晰的方式来捕获异常。但是你必须用Throwable替换默认的Exception。

try {
    /* something */
} catch (AError | BError) {
    handler1()
} catch (Throwable) {
    handler2()
}

从PHP 7.1开始,

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

有趣的是,你还可以:

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

在PHP的早期版本中:

catch(Exception $ex){
    if($ex instanceof AError || $ex instanceof BError){
        //handle AError and BError
    } elseif($ex instanceof CError){
        //handle CError
    } else {
       throw $ex; // an unknown exception occurred, throw it further
    }
}

作为可接受答案的扩展,您可以切换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;

    }

}

这里没有列出的另一个选项是使用异常的code属性,所以你可以这样做:

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

嗯,有很多解决方案是为低于7.1的php版本编写的。

下面是另一个简单的方法,适用于那些不想catch all异常且不能创建公共接口的人:

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