在一个catch块中捕获多个exceptiontypes

我想要一个更清晰的方法来获得以下function,在一个块中捕获AErrorBError

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

有没有办法做到这一点? 还是我必须分开抓住他们?

AErrorBerror有一个共享的基类,但是他们也将其与我想要处理的其他types分享给handler2 ,所以我不能只抓基类。

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

如果你不能,你可以尝试使用Exception来捕获所有的Exception ,然后检查使用instanceof抛出了哪个exception。

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

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

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

尽pipe还有其他的答案,你可以在同一个块中捕获AErrorBError (如果你是定义exception的BError ,那么它会更容易些)。 即使考虑到有些例外,你仍然应该能够定义一个等级来满足你的需求。

 abstract class MyExceptions extends \Exception {} abstract class LetterError extends MyExceptions {} class AError extends LetterError {} class BError extends LetterError {} 

然后:

 catch(LetterError $e){ //voodoo } 

正如你可以在这里和这里看到的,即使是SPL缺省exception也有一个层次可以利用。 另外,正如PHP手册所述 :

当引发exception时,语句后面的代码将不会被执行, 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) {} 

当涉及到exception时使用OOP非常强大。 使用诸如get_classinstanceof类的东西都是黑客行为,如果可能的话应该避免使用。

我想补充的另一个解决scheme是将exception处理function放在自己的方法中。

你可以有

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

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

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

这样,如果你的exception处理机制需要改变,你仍然只有一个单独的代码位置,你正在使用OOP的一般结构。

来到PHP 7.1是捕捉多种types的能力。

所以这个:

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

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

在function上是等同的。

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

本文涵盖了electrictoolbox.com/php-catch-multiple-exception-types的问题。 直接从文章复制的post的内容:

示例例外

以下是针对此示例定义的一些示例exception:

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

处理多个例外

这非常简单 – 每个可以引发的exceptiontypes都可以有一个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 } 

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

作为被接受的答案的延伸,你可以切换exception的types,产生一个类似于原始例子的模式:

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

如果您无法控制定义例外,那么这是一个合理的select。 使用exceptionvariables的名称将exception分类。 然后在try / catch块之后检查exceptionvariables。

 $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块实现之间有很多重复,这种看起来有些奇怪的方法可能是值得的。

除了翻转之外,还可以通过使用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"; } 

3v4l.org

一个好方法是使用set_exception_handler

警告!!! 用PHP 7,你可能会因为致命的错误而死亡。 例如,如果您在非对象上调用某个方法,通常会遇到Fatal error: Call to a member function your_method() on null ,如果错误报告处于打开状态,您将会看到这一点。

上面的错误不会被捕获catch(Exception $e) 。 上述错误不会触发由set_error_handler设置的任何自定义error handling程序。

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

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

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

通常情况下,如果你需要有多个catch块,你的代码有什么问题,而且你没有遵循单一的责任原则。 如果你发现自己处于这样的位置,你应该总是重构。