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

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

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

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


当前回答

如果您无法控制异常的定义,这里有一个合理的替代方案。在捕获异常时,使用异常变量的名称对异常进行分类。然后在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);
}

这种看起来有点奇怪的方法可能只在catch块实现之间存在大量重复的情况下才有价值。

其他回答

这里没有列出的另一个选项是使用异常的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
    }
}

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

    }

}

除了穿越,也可以使用goto跨过去。 如果你想看世界燃烧,这很有用。

<?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";
}

3 v4l.org

本文讨论的问题是electrictoolbox.com/php-catch-multiple-exception-types。文章内容直接复制:

例异常

以下是为本例的目的而定义的一些示例异常:

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

处理多个异常

这很简单——对于每个可以抛出的异常类型都可以有一个catch块:

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
}

如果抛出了一个没有被任何其他catch语句处理的异常,它将被catch(exception $e)块处理。它不一定是最后一个。

如果您无法控制异常的定义,这里有一个合理的替代方案。在捕获异常时,使用异常变量的名称对异常进行分类。然后在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);
}

这种看起来有点奇怪的方法可能只在catch块实现之间存在大量重复的情况下才有价值。