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

Dom*_*rto 225 php exception-handling

我想一个更清洁的方式来获得以下功能,捕捉AErrorBError在一个块:

try
{
    /* something */
}
catch( AError, BError $e )
{
    handler1( $e )
}
catch( Exception $e )
{
    handler2( $e )
}
Run Code Online (Sandbox Code Playgroud)

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

AError并且Berror有一个共享的基类,但是它们也与我想要的其他类型共享它handler2,所以我不能只捕获基类.

Mir*_*ate 304

更新:

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

语法是:

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

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 {}
Run Code Online (Sandbox Code Playgroud)

然后:

catch(LetterError $e){
    //voodoo
}
Run Code Online (Sandbox Code Playgroud)

正如您在此处此处所看到的,即使是SPL默认异常也可以使用您可以利用的层次结构.另外,如PHP手册中所述:

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

这意味着你也可以拥有

class CError extends LetterError {}
Run Code Online (Sandbox Code Playgroud)

你需要处理不同于AError或者BError,让你的catch语句应该是这样的:

catch(CError $e){
    //voodoo
}
catch(LetterError $e){
    //voodoo
}
Run Code Online (Sandbox Code Playgroud)

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

interface Group1 {}

class AError extends LetterError implements Group1 {}

class BError extends LetterError implements Group1 {}
Run Code Online (Sandbox Code Playgroud)

然后:

catch (Group1 $e) {}
Run Code Online (Sandbox Code Playgroud)

在涉及异常时使用OOP非常强大.使用像get_class或者instanceof是黑客的东西,如果可能的话应该避免使用.

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

你可以有

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

function handleExceptionMethod2(Exception $e)
{
    //voodoo
}
Run Code Online (Sandbox Code Playgroud)

假设是绝对没有办法,你可以控制的异常类层次结构或接口(也有几乎总是是一个方法),你可以做到以下几点:

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);
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,如果您的异常处理机制需要更改,并且您正在OOP的常规构造中工作,那么您仍然只需要修改一个代码位置.

  • 这是对此的另一次投票作为正确的答案.不幸的是,在接受的答案中所说的内容以及它被接受为正确答案的事实,正是使PHP成为疯狂的原因. (4认同)
  • 这不是公认的答案,因为当您使用第三方库时,您无法做到这一点. (3认同)

ale*_*lex 228

在PHP的最新版本中,这是可能的.请参阅以下答案.


如果您可以修改例外,请使用此答案.

如果你不能,你可以尝试捕获所有,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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是如前面的答案所述,使用多个catch块可能会更好.

try
{
    /* something */
}
catch( AError $e )
{
   handler1( $e );
}
catch ( BError $b )
{
   handler2( $e );
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您在这里阅读第一段:http://php.net/manual/en/language.exceptions.php您将看到多个catch块是可能的并且是完全有效的解决方案.OP虽然错误地将两个异常类放在一个catch语句中.我认为用更多的catch块更新你的答案会更好. (11认同)
  • 但是不要忘记这会捕获所有异常,所以应该有类似`...} else {throw($ e); 如果它与两者不匹配.对不起,可能是错误的语法,没看到php一段时间. (7认同)
  • 这就是我所害怕的.如果有许多错误类型需要一起处理,将它们集中在一起并测试类型会很好,但是对于只有2个,例如在我的情况下,单独捕获它们可能更清晰.谢谢! (6认同)
  • 建议一个吃掉你所有其他例外的解决方案,根本不应该被接受...... (4认同)
  • @DominicGurto:是的,我也会这样做:)我更关心PHP对'finally`声明的态度.;) (3认同)

Joe*_*ins 88

即将在PHP 7.1是捕获多种类型的能力.

这样:

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

<?php
try {

} catch (FirstException | SecondException $ex) {
    $this->manageException($ex);
}
?>
Run Code Online (Sandbox Code Playgroud)

功能相同.


han*_*rik 42

从PHP 7.1开始,

catch( AError | BError $e )
{
    handler1( $e )
}
Run Code Online (Sandbox Code Playgroud)

有趣的是,您还可以:

catch( AError | BError $e )
{
    handler1( $e )
} catch (CError $e){
    handler2($e);
} catch(Exception $e){
    handler3($e);
}
Run Code Online (Sandbox Code Playgroud)

在早期版本的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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • Upvoted用于解释较旧和较新的PHP版本 (3认同)

小智 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
  }
}
Run Code Online (Sandbox Code Playgroud)

处理多个异常

它非常简单 - 可以抛出每个异常类型的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
}
Run Code Online (Sandbox Code Playgroud)

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

  • 当您必须为两个或更多不同的异常执行相同的代码时,会出现此方法的问题. (3认同)

smi*_*x96 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;

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 使用多个捕获而不是此解决方案. (6认同)

del*_*ala 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);
}
Run Code Online (Sandbox Code Playgroud)

如果catch块实现之间存在大量重复,那么这种有点奇怪的方法可能是值得的.


Jso*_*owa 5

从 PHP 8.0 开始,当您不需要输出错误内容(来自变量$e)时,您可以使用更干净的方式来捕获异常。但是您必须将默认值替换ExceptionThrowable.

try {
    /* something */
} catch (AError | BError) {
    handler1()
} catch (Throwable) {
    handler2()
}
Run Code Online (Sandbox Code Playgroud)

  • 不可以,在以前的版本中,您必须编写变量名称“AError $e”。 (2认同)