2014-12-07 79 views
1

我想捕获一个自定义异常,对其执行一些逻辑,如果失败,则将其抛入更通用的catch块。像这样:抛出下一个捕获块的例外

class My_Exception extends Exception { 
    protected $_nonFatal = false; 

    public function __construct($value, $nonFatal = false) { 
     $this->_nonFatal = (bool)$nonFatal; 

     return parent::__construct($value); 
    } 

    public function isNonFatal() { 
     return (bool)$this->_nonFatal; 
    } 
} 

try { 

} catch (My_Exception $e) { 
    if ($e->isNonFatal) { 
     // #1 
     // Err gently 
    } 

    // #2 
    // The error was fatal, so keep throwing it 
    throw new Exception($e->getMessage()); 

} catch (Exception $e) { 
    // #3 
    echo 'An exception was caught with the message '.$e->getMessage(); 
} 

所以我赶上My_Exception,检查,看它是否是一个非致命错误。如果是这样,请轻轻地,(第一节)。如果没有(第2节),我希望触发第二次捕获(第3节)。相反,第2节中的throw new Exceptiontry/catch/catch全部保留在一起。

我可以在类$e上使用switch语句,但我认为这样更加混乱。有没有一个标准的方法来做到这一点,我错过了?

回答

2

如果不是(第2号),我想被触发,第二抓

try/catch块不喜欢的工作 - 一个catch块将永远摆脱试试/抓块;它不会像开关语句那样“跌倒”。

你需要用另一个try/catch块来包装你的代码。

try { 
    try { 
     // ... 
    } catch (My_Exception $e) { 
     if ($e->isNonFatal) { 
      // #1 
      // Err gently 
     } 

     // #2 
     // The error was fatal, so keep throwing it 
     throw new Exception($e->getMessage()); 
    } 
} catch (Exception $e) { 
    // #3 
    echo 'An exception was caught with the message '.$e->getMessage(); 
} 

有没有做到这一点的标准方式我失踪?

没有真正的“标准”方式来做到这一点;通常你不会用另一个异常概括异常,但如果应用程序是正确的,那么这就是你想要做的事情。

管理异常链的更好方法是在构造函数中使用pass your custom exception a the previous exception。这样,有一个机会可以挑选异常可能使用Exception.getPrevious(),并显示您的例外与更通用的例外。

1

不幸的是,即使从其他函数调用中引发,catch块也不能处理在前面的兄弟catch块中抛出的任何异常。
换句话说,从内侧catch块#1抛出的任何未处理的异常将是不可见从内部块#2 (而是将通过在调用栈中的连上catch块进行处理)

try { 
    error_prone_code(); 
} catch (My_Exception $e) { // #1 
    throw new \Exception($e->getMessage()); 
} catch (Exception $e) { // #2 
    echo "Something bad happend: {$e->getMessage()}"; 
} 

然后,坦率地说,立即嵌套try/catch块看起来相当难看。
如果您的应用程序逻辑不太复杂,可以使用instanceof运算符来保持代码整洁。

try { 
    error_prone_code(); 
// Make sure to catch the standard Exception base class 
} catch (\Exception $e) { 
    // instanceof operator tells if object: 
    // is an instance of a specific class 
    // is an instance of some class that extends the mentionned class 
    // 's class implements a specific interface 
    if (! $e instanceof My_Exception || ! $e->isNonFatal()) { 
     echo "Fatal exception arose: {$e->getMessage()}"; 
     // You may also throw the same exception to some catch block upper in the call stack. 
     // throw $e; 
    } else { 
     // Gentle handling 
    } 
}