在一个catch块中捕获多个异常类型

时间:2011-12-09 00:22:38

标签: php exception-handling

我想要一种更简洁的方法来获取以下功能,以便在一个块中捕获AErrorBError

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

有没有办法做到这一点?或者我必须单独抓住它们?

AErrorBerror有一个共享的基类,但是它们也与我想要传递给handler2的其他类型共享它,所以我不能只抓住它基类。

12 个答案:

答案 0 :(得分:260)

更新

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

语法为:

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

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

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


对于7.1之前的PHP:

尽管这些其他答案都说明了,但您可以在同一个块中捕获AErrorBError(如果您是定义异常的那个,则会更容易一些)。即使你有想要“落伍”的例外情况,你仍然可以定义一个符合你需求的层次结构。

abstract class MyExceptions extends Exception {}

abstract class LetterError extends MyExceptions {}

class AError extends LetterError {}

class BError extends LetterError {}

然后:

catch(LetterError $e){
    //voodoo
}

正如您可以看到herehere,即使SPL默认例外也有您可以利用的层次结构。另外,如PHP Manual中所述:

  

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

这意味着你也可以

class CError extends LetterError {}

您需要处理的方式与AErrorBError不同,因此您的catch语句将如下所示:

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

如果你遇到了二十个或更多合法属于同一个超类的异常的情况,并且你需要以一种方式处理五个(或任何大型组)其他方式,那么你仍然可以这样做。

interface Group1 {}

class AError extends LetterError implements Group1 {}

class BError extends LetterError implements Group1 {}

然后:

catch (Group1 $e) {}

在异常方面使用OOP非常强大。使用诸如get_classinstanceof之类的东西是黑客攻击,如果可能应该避免使用。

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

你可以

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的常规构造中工作,那么您仍然只需要修改一个代码位置。

答案 1 :(得分:221)

在PHP> = 7.1中,这是可能的。请参阅下面的answer


如果您可以修改例外,use this answer

如果你不能,你可以尝试使用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;
    }
}

但是 use multiple catch blocks as described in aforementioned answer可能会更好。

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

答案 2 :(得分:88)

进入PHP 7.1是捕捉多种类型的能力。

这样:

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

<?php
try {

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

功能相同。

答案 3 :(得分:42)

自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){
        //handle a AError
    } elseif($ex instanceof BError){
        //handle a BError
    } else {
       throw $ex;//an unknown exception occured, throw it further
    }
}

答案 4 :(得分:25)

本文介绍了问题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)块处理。它不一定是最后一个。

答案 5 :(得分:21)

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

    }

}

答案 6 :(得分:5)

如果您无法控制定义异常,那么这是一个合理的替代方案。使用异常变量的名称可以在捕获异常时对异常进行分类。然后在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块实现之间存在大量重复,这种有点奇怪的方法可能是值得的。

答案 7 :(得分:3)

除了堕落之外,还可以使用转到来跳过。 如果你想看到世界燃烧,这是非常有用的。

@Component({
  selector: 'dropdown',
  template: `
    <div>Test</div>
  `
})
export class DropdownComponent {
  constructor(public data:RouteParams) {
  }
}

3v4l.org

答案 8 :(得分:1)

一个好方法是使用.evenspecificerer { color:black !important; }

警告!!!使用PHP 7,您可能会因致命错误而死亡。例如,如果您在非对象上调用方法,通常会获得set_exception_handler,如果启用了错误报告,您可能会看到此内容。

上述错误不会被Fatal error: Call to a member function your_method() on null捕获。 上述错误不会触发catch(Exception $e)设置的任何自定义错误处理程序。

您必须使用set_error_handler来捕获PHP7中的错误。 。 这可能会有所帮助:

catch(Error $e){ }

答案 9 :(得分:0)

此处未列出的另一个选项是使用异常的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
    }
}

答案 10 :(得分:0)

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

对于那些不想捕获所有异常并且无法建立通用接口的人来说,这是另一个简单的:

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

答案 11 :(得分:0)

从PHP 8.0开始,您可以使用更简洁的方法来捕获异常。但是,您必须将默认Exception替换为Throwable

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