如何更改Exception对象的异常消息?

时间:2011-12-08 11:33:10

标签: php

所以我捕获一个异常(异常类的实例),我想要做的是更改它的异常消息。

我可以像这样得到异常消息:

$e->getMessage();

但是如何设置异常消息?这不起作用:

$e->setMessage('hello');

11 个答案:

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