2011-12-08 88 views
10

因此,我捕捉到一个异常(Exception类的实例),我想要做的是更改它的异常消息。如何更改异常对象的异常消息?

我能得到这样的异常消息:

$e->getMessage(); 

但是如何设置一个例外消息?这将不起作用:

$e->setMessage('hello'); 
+1

更改异常消息(几乎总是)没有意义。你为什么想这样做? – Corbin

+0

@Corbin嗯,我正在维护一个旧的遗留系统。我需要在不改变大量代码的情况下解决某个bug,因为这需要大量的没有时间的新测试。基本上改变一个异常信息是修复这个错误的最麻烦和侵入性的方法(非常丑陋,但功能性最重要)。 –

+0

对于那些已回答抛出新异常的应用程序,您将丢失具有原始异常的堆栈跟踪。因此,如果代码中出现异常(从库代码中抛出),则可能需要处理原始异常,以便其他层可以正确解释它,同时保持堆栈跟踪完好无损。 –

回答

7

您无法更改异常消息。

然而,你可以确定它是类名和代码,并抛出一个新的,同一类,相同的代码,但有不同的消息。

+1

是的,你可以看到我的答案:http://stackoverflow.com/a/20441768/582917 – CMCDragonkai

+0

当然,异常消息可以被覆盖。这个答案不应该被接受。 – Fahmi

1

您无法更改由Exception类给出的消息。如果您想要自定义消息,则需要使用$ e-> getCode()检查错误代码并创建自己的消息。

-1

你可以用自己的扩展异常,并投入了先导作用,它

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

由于某些原因,不幸的是getMessage()在PHP中被声明为final,并且上面的代码不起作用。 – romaninsh

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(); 
} 
+0

像这样重新抛出的问题是你失去堆栈跟踪 –

3

您可以扩展异常并使用parent :: __构造来设置您的消息。这解决了您无法重写getMessage()的问题。

class MyException extends Exception { 
    function __construct() { 
     parent::__construct("something failed or malfunctioned."); 
    } 
} 
+0

这不能解决OP的问题。他们想要更改现有异常的消息,而不是使用硬编码消息创建新消息。 –

+0

您无法更改异常消息。选举委员会通过接受这样的答复来承认这一点。 –

13

只要做到这一点,它的工作原理我测试了它。

<?php 

class Error extends Exception{ 

    public function setMessage($message){ 
     $this->message = $message; 
    } 

} 

$error = new Error('blah'); 

$error->setMessage('changed'); 

throw $error; 
+1

+1。为了避免混淆,我会将其命名为“Error”以外的其他名称,但我假设这仅仅是为了举例。 –

+0

PHP中没有本地错误类,所以可以创建自己的错误处理设置。 – CMCDragonkai

+5

错误总是一个保留字,并且现在有一个[Error Class](http://php.net/manual/en/class.error.php)(后者是@ CMCDragonkai制作时不存在的东西他们在2014年的评论,尽管前者依然如此)。 – DanielM

0

这里是我正在使用的一个generified片段。

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

对于几乎在阳光下的每一个案件,您应该抛出一个新的例外与旧的例外附加。

try { 
    dodgyCode(); 
} 
catch(\Exception $oldException) { 
    throw new MyException('My extra information', 0, $oldException); 
} 

Every在一段时间一次虽然,你真正需要处理到位的例外,因为抛出另一个异常是不是你真正想做的事。

一个很好的例子是BehatFeatureContext当你想附加@AfterStep方法的附加信息。在一个步骤失败后,您可能希望截取屏幕截图,然后向输出添加一条消息,以了解可以看到截图的位置。

因此,为了改变异常的消息,在那里你可以取代它,你不能把一个新的异常,你可以使用反射来暴力破解的参数值:

$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

+0

这是非常感谢 –

+0

这应该是公认的答案,这是更有用和预期 – newms87

+0

谢谢你,很高兴听到@ newms87。为了对接受其他答案的人公平,我的回答已经太晚了。 ;) – DanielM

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

你应该在非常特殊的情况下明智地使用这个垃圾,当你没有任何其他选择。