所以我捕获一个异常(异常类的实例),我想要做的是更改它的异常消息。
我可以像这样得到异常消息:
$e->getMessage();
但是如何设置异常消息?这不起作用:
$e->setMessage('hello');
答案 0 :(得分:19)
只要这样做,我就可以测试它。
<?php
class Error extends Exception{
public function setMessage($message){
$this->message = $message;
}
}
$error = new Error('blah');
$error->setMessage('changed');
throw $error;
答案 1 :(得分:17)
对于几乎所有在阳光下的情况,你应该抛出一个新的Exception并附上旧的Exception。
try {
dodgyCode();
}
catch(\Exception $oldException) {
throw new MyException('My extra information', 0, $oldException);
}
每隔一段时间,你确实需要操作异常,因为抛出另一个异常并不是你想要做的事情。
当您想要在FeatureContext
方法中附加其他信息时,Behat @AfterStep
就是一个很好的例子。在步骤失败后,您可能希望截取屏幕截图,然后在输出中添加一条消息,以查看可以看到屏幕截图的位置。
因此,为了更改Exception的消息,您只需替换它,并且无法抛出新的异常,您可以使用反射来强制参数值:
$message = " - My appended message";
$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
以下是Behat的例子:
/**
* Save screen shot on failure
* @AfterStep
* @param AfterStepScope $scope
*/
public function saveScreenShot(AfterStepScope $scope) {
if (!$scope->getTestResult()->isPassed()) {
try {
$screenshot = $this->getSession()->getScreenshot();
if($screenshot) {
$filename = $this->makeFilenameSafe(
date('YmdHis')."_{$scope->getStep()->getText()}"
);
$filename = "{$filename}.png";
$this->saveReport(
$filename,
$screenshot
);
$result = $scope->getTestResult();
if($result instanceof ExceptionResult && $result->hasException()) {
$exception = $result->getException();
$message = "\nScreenshot saved to {$this->getReportLocation($filename)}";
$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
}
}
}
catch(UnsupportedDriverActionException $e) {
// Overly specific catch
// Do nothing
}
}
}
同样,如果你能避免,你就不应该这样做。
来源:My old boss
答案 2 :(得分:6)
您无法更改异常消息。
然而,您可以确定它的类名和代码,并使用相同的代码但使用不同的消息抛出相同类的新类。
答案 3 :(得分:5)
您可以扩展Exception并使用parent :: __构造来设置消息。这可以解决您无法覆盖getMessage()的问题。
class MyException extends Exception {
function __construct() {
parent::__construct("something failed or malfunctioned.");
}
}
答案 4 :(得分:3)
这是我使用的一个广泛的片段。
foreach ($loop as $key => $value)
{
// foo($value);
thow new Special_Exception('error found')
}
catch (Exception $e)
{
$exception_type = get_class($e);
throw new $exception_type("error in $key :: " . $e->getMessage());
}
答案 5 :(得分:1)
您无法更改Exception类提供的消息。如果您想要自定义消息,则需要使用$ e-&gt; getCode()检查错误代码并创建自己的消息。
答案 6 :(得分:1)
如果你真的想这样做(在唯一的情况下,我可以认为你可能想要这样做),你可以重新抛出异常:
function throwException() {
throw new Exception( 'Original' );
}
function rethrowException() {
try {
throwException();
} catch( Exception $e ) {
throw new Exception( 'Rethrow - ' . $e->getMessage() );
}
}
try {
rethrowException();
} catch( Exception $e ) {
echo $e->getMessage();
}
答案 7 :(得分:0)
如果您不知道您正在处理哪种异常(可以拥有自己的属性),那么丑陋的黑客就是使用反射。
try {
// business code
} catch (\Exception $exception) {
$reflectedObject = new \ReflectionClass(get_class($exception));
$property = $reflectedObject->getProperty('message');
$property->setAccessible(true);
$property->setValue($exception, "new message");
$property->setAccessible(false);
throw $exception;
}
当你没有别的选择时,你应该在非常具体的情况下明智地使用这个垃圾。
答案 8 :(得分:0)
php Exception类具有一个__toString()
方法,这是Exception类中唯一不是final
的方法,这意味着可以对其进行自定义。
class HelloMessage extends Exception {
function __toString() {
return $this->getMessage()." you have an error with code: ".$this->getCode();
}
}
您可以在try-catch
块中按以下方式使用它:
try {
if (2 > 0) {
throw new HelloMessage("Hello", 10);
}
} catch (HelloMessage $e) {
echo $e;
}
输出为:
Hello you have an error with code: 10
答案 9 :(得分:-1)
您可以使用自己的方式扩展Exception,并在其中放置一个setter
class MyException extends Exception
{
private $myMessage = '';
public function getMessage()
{
if ($this->myMessage === '') {
return parent::getMessage();
} else {
return $this->myMessage;
}
public function setMessage($msg)
{
$this->myMessage = $msg;
}
}
答案 10 :(得分:-1)
这是 David Chan 的答案的改进版本。这是一个重新抛出解决方案,它使用get_class
重新抛出相同的异常类型,并且即使将ErrorException
包含六个而不是三个构造函数参数,也将所有参数传递给构造函数。 / p>
foreach ($loopvar as $key => $value)
{
doSomethingThatMightThrow($value);
}
catch (\Exception $e)
{
$exception_type = get_class($e);
$new_message = "[key '" . $key . "'] " . $e->getMessage();
if ($e instanceof \ErrorException) {
throw new $exception_type($new_message, $e->getCode(), $e->getSeverity(), $e->getFile(), $e->getLine(), $e);
}
throw new $exception_type($new_message, $e->getCode(), $e);
}