Как изменить сообщение об исключении объекта Exception?

Итак, я поймаю исключение (экземпляр класса Exception), и то, что я хочу сделать, это изменить его сообщение об исключении.

Я могу получить сообщение об исключении, подобное этому:

$e->getMessage();

Но как установить сообщение об исключении? Это не сработает:

$e->setMessage('hello');

Ответ 1

Вы не можете изменить сообщение об исключении.

Однако вы можете определить его имя и код класса и выбросить новый, одного и того же класса с тем же кодом, но с другим сообщением.

Ответ 2

Просто сделайте это, он работает, я его протестировал.

<?php

class Error extends Exception{

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

}

$error = new Error('blah');

$error->setMessage('changed');

throw $error;

Ответ 3

Для почти каждого отдельного случая под солнцем вы должны выбросить новое Исключение с прикрепленным старым Исключением.

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

Каждый раз в то время, хотя вам действительно нужно манипулировать Исключением на месте, потому что бросать другое исключение - это не то, что вы хотите сделать.

Хорошим примером этого является Behat FeatureContext, когда вы хотите добавить дополнительную информацию в метод @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
            }
        }
    }

Опять же, вы не должны этого делать, если можете избежать этого.

Источник: Мой старый босс

Ответ 4

Вы можете расширить Exception и использовать конструкцию parent:: __ для установки своего сообщения. Это обостряет тот факт, что вы не можете переопределить getMessage().

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

Ответ 5

Вы не можете изменить сообщение, указанное классом Exception. Если вам нужно специальное сообщение, вам нужно будет проверить код ошибки с помощью $e- > getCode() и создать собственное сообщение.

Ответ 6

Если вы действительно хотели это сделать (в единственной ситуации, я могу думать, что вы можете это сделать), вы можете повторно выбросить исключение:

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

здесь представлен обобщенный фрагмент.

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

Ответ 8

Уродливый взлом, если вы не знаете, какое исключение вы обрабатываете (которое может иметь свои собственные свойства) - использовать отражение.

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

Вы должны использовать это дерьмо мудро в очень конкретном случае, когда у вас нет другого выбора.

Ответ 9

Вы можете расширить Exception своим собственным и поместить в него установщик

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