在一个catch块中捕获多个exceptiontypes
我想要一个更清晰的方法来获得以下function,在一个块中捕获AError
和BError
:
try { /* something */ } catch( AError, BError $e ) { handler1( $e ) } catch( Exception $e ) { handler2( $e ) }
有没有办法做到这一点? 还是我必须分开抓住他们?
AError
和Berror
有一个共享的基类,但是他们也将其与我想要处理的其他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还有其他的答案,你可以在同一个块中捕获AError
和BError
(如果你是定义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 {}
你需要处理不同于AError
或BError
,所以你的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_class
或instanceof
类的东西都是黑客行为,如果可能的话应该避免使用。
我想补充的另一个解决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块,你的代码有什么问题,而且你没有遵循单一的责任原则。 如果你发现自己处于这样的位置,你应该总是重构。