Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/242.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何更改异常对象的异常消息?_Php - Fatal编程技术网

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

Php 如何更改异常对象的异常消息?,php,Php,所以我捕获了一个异常(exception类的实例),我想做的是更改它的异常消息 我可以得到如下异常消息: $e->getMessage(); 但是如何设置异常消息呢?这行不通: $e->setMessage('hello'); 您无法更改异常消息 但是,您可以确定它的类名和代码,并抛出一个新的,属于同一个类,具有相同的代码,但具有不同的消息。您不能更改异常类给出的消息。如果需要自定义消息,则需要使用$e->getCode()检查错误代码并创建自己的消息。您可以使用自己的消息扩展E

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

我可以得到如下异常消息:

$e->getMessage();
但是如何设置异常消息呢?这行不通:

$e->setMessage('hello');

您无法更改异常消息


但是,您可以确定它的类名和代码,并抛出一个新的,属于同一个类,具有相同的代码,但具有不同的消息。

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

您可以使用自己的消息扩展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;
  }
}

如果您真的想这样做(在我认为您可能想这样做的唯一情况下),您可以重新抛出异常:

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

您可以扩展异常并使用父::\构造来设置消息。这绕过了无法重写getMessage()的事实


只要这样做,就行了,我测试过了

<?php

class Error extends Exception{

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

}

$error = new Error('blah');

$error->setMessage('changed');

throw $error;

这里是我正在使用的一个通用代码段

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

对于几乎所有情况,您都应该抛出一个新异常,并附加旧异常

try {
    dodgyCode();
}
catch(\Exception $oldException) {
    throw new MyException('My extra information', 0, $oldException);
}
不过,每隔一段时间,您确实需要就地操作一个异常,因为抛出另一个异常实际上并不是您想要做的

一个很好的例子是在
FeatureContext
中,当您想在
@AfterStep
方法中附加额外信息时。步骤失败后,您可能希望拍摄一个屏幕截图,然后在输出中添加一条消息,说明在哪里可以看到该屏幕截图

因此,为了更改异常的消息,您可以替换它,而不能抛出新的异常,您可以使用反射强制参数值:

$message = " - My appended message";

$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
下面是上下文中的行为示例:

    /**
     * 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
            }
        }
    }
再说一次,如果你能避免的话,你永远不应该这样做


来源:

如果你不知道你正在处理的异常类型(可能有自己的属性)是使用反射,那么这是一个丑陋的黑客行为

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

当你没有其他选择时,你应该在非常特殊的情况下明智地使用这些废话。

这是陈大卫答案的改进版本。这是一个重新抛出的解决方案,它使用
get\u class
重新抛出相同的异常类型,并将所有参数传递给构造函数,即使在的情况下,构造函数也有六个而不是三个构造函数参数

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

php异常类有一个
\uuu toString()
方法,这是异常类中唯一一个不是
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


更改异常消息(几乎总是)没有意义。你为什么要这么做?@Corbin嗯,我正在维护一个旧的遗留系统。我需要在不改变大量代码的情况下解决某个bug,因为它需要大量新的测试,而没有时间。基本上,更改异常消息是修复bug的最简单、最不麻烦的方法(非常难看,但功能性很强,这是目前最重要的问题)。对于那些响应抛出新异常的人,您将丢失原始异常的堆栈跟踪。因此,如果在代码中捕获到从库代码抛出的异常,您可能需要处理原始异常,以便其他层可以正确解释它,同时保持堆栈跟踪不变。不幸的是,由于某种原因,getMessage()在PHP中声明为final,上述代码无法工作。+1。为了避免混淆,我会将其命名为“Error”以外的名称,但我假设这只是为了示例。PHP中没有本机Error类,因此可以创建自己的错误处理设置。Error始终是一个保留字,现在有一个(后者在2014年@cmcdragokai发表评论时并不存在,尽管前者仍然成立)。此方法要求您同时控制引发异常的代码,但情况可能并非如此。类似重试的问题是,您丢失了进程异常消息的堆栈跟踪。此答案不应被接受。这无法解决OP的问题。他们希望更改exist的消息正在处理异常,而不是使用硬编码消息创建新的异常。您不能更改异常的消息。OP通过接受这样的答案来确认这一点。这应该是被接受的答案,这更有用,更值得期待谢谢,很高兴听到@newms87。不过,为了公平对待接受另一个答案的人,我的答案你能解释一下为什么你称这个解决方案为“丑陋的”吗“hack?使用
ReflectionClass
是一种不好的做法吗?您的解决方案似乎比所有其他Anwser更干净,因为它涵盖了所有可能的
异常
子类构造函数参数。的确,如果您需要更改私有属性的属性,这意味着您有严重的架构设计问题。考虑到在使用此解决方案之前进行er重构(例如:从抛出异常的位置抛出具有正确属性的正确异常,或者捕获它们自己块中的所有预期异常…)。当然,如果你需要应用一些通用逻辑来处理宇宙,那么这个解决方案可能是有效的。你甚至可以用
\Throwable
而不是
\Exception
来获得更通用的解决方案。选民们:请指出这个答案有什么问题。这是最干净、最通用的回答,尤其是当您希望保留异常类型,而不必求助于反射。
Hello you have an error with code: 10