Ответ 1
Вы не можете изменить сообщение об исключении.
Однако вы можете определить его имя и код класса и выбросить новый, одного и того же класса с тем же кодом, но с другим сообщением.
Итак, я поймаю исключение (экземпляр класса Exception), и то, что я хочу сделать, это изменить его сообщение об исключении.
Я могу получить сообщение об исключении, подобное этому:
$e->getMessage();
Но как установить сообщение об исключении? Это не сработает:
$e->setMessage('hello');
Вы не можете изменить сообщение об исключении.
Однако вы можете определить его имя и код класса и выбросить новый, одного и того же класса с тем же кодом, но с другим сообщением.
Просто сделайте это, он работает, я его протестировал.
<?php
class Error extends Exception{
public function setMessage($message){
$this->message = $message;
}
}
$error = new Error('blah');
$error->setMessage('changed');
throw $error;
Для почти каждого отдельного случая под солнцем вы должны выбросить новое Исключение с прикрепленным старым Исключением.
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
}
}
}
Опять же, вы не должны этого делать, если можете избежать этого.
Источник: Мой старый босс
Вы можете расширить Exception и использовать конструкцию parent:: __ для установки своего сообщения. Это обостряет тот факт, что вы не можете переопределить getMessage().
class MyException extends Exception {
function __construct() {
parent::__construct("something failed or malfunctioned.");
}
}
Вы не можете изменить сообщение, указанное классом Exception. Если вам нужно специальное сообщение, вам нужно будет проверить код ошибки с помощью $e- > getCode() и создать собственное сообщение.
Если вы действительно хотели это сделать (в единственной ситуации, я могу думать, что вы можете это сделать), вы можете повторно выбросить исключение:
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();
}
здесь представлен обобщенный фрагмент.
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 {
// 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;
}
Вы должны использовать это дерьмо мудро в очень конкретном случае, когда у вас нет другого выбора.
Вы можете расширить 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;
}
}