Страница 1 из 1
Дружественные исключения
Добавлено: 2019.09.20, 18:57
samdark
Идея "дружественного исключения" в том, что можно реализовать интерфейс
FriendlyExceptionInterface(
https://github.com/yiisoft/friendlyexce ... erface.php) и предоставить для исключения описание того, как решить возникшую проблему. Обработчик ошибок, соответственно, может эту информацию показывать на экране ошибки вместе с обычными трейсами.
Изначально интерфейс был частью пакета yii-web, в котором уже есть обработчик, способный отображать дополнительную информацию, но, подумаю пару дней, я понял что интерфейс полезен для консольных приложений и использования вне Yii.
Итак, самый маленький пакет Yii 3:
https://github.com/yiisoft/friendlyexception
Что думаете?
Re: Дружественные исключения
Добавлено: 2019.09.20, 19:48
yiiliveext
А какие мысли вы ожидаете? Сделать ревью кода?
Re: Дружественные исключения
Добавлено: 2019.09.20, 20:27
samdark
1. Втащили бы себе в проект?
2. Достаточно ли такого интерфейса?
Re: Дружественные исключения
Добавлено: 2019.09.20, 21:54
yiiliveext
samdark писал(а): ↑2019.09.20, 20:27
1. Втащили бы себе в проект?
2. Достаточно ли такого интерфейса?
Давайте на примере. Допустим мы в консоли ввели команду ./yii myservice/updat вместо ./yii myservice/update. Нам нужно в решении предложить правильную команду. Как мы это сможем сделать?
Re: Дружественные исключения
Добавлено: 2019.09.20, 22:53
samdark
Re: Дружественные исключения
Добавлено: 2019.09.20, 23:02
yiiliveext
И? Где вы здесь хотите использовать getSolution? По факту это часть getMessage, которую можно выводить отдельно. Остальное все равно реализовывается отдельно в частных исключениях.
Re: Дружественные исключения
Добавлено: 2019.09.21, 00:14
samdark
Не понял вопроса. Я не хочу использовать в исключении getSolution(), я его реализую в нём. getSuggestedAlternatives() в этом случае это как раз и есть getSolution().
По факту это часть getMessage, которую можно выводить отдельно.
Если отдельно, то не часть getMessage(). Например, getMessage() пишется в лог, а getSolution() уж точно в логе не место.
Остальное все равно реализовывается отдельно в частных исключениях.
Вот это совсем не понял
Что остальное и в каких исключениях?
Re: Дружественные исключения
Добавлено: 2019.09.21, 14:59
yiiliveext
samdark писал(а): ↑2019.09.21, 00:14
Не понял вопроса. Я не хочу использовать в исключении getSolution(), я его реализую в нём. getSuggestedAlternatives() в этом случае это как раз и есть getSolution().
Именно об этом я и говорю, getSolution() должен быть универсальным, а значит должен работать с контекстом. Потому что getSuggestedAlternatives() работает с контекстом (команда/роут). Значит нам нужен контекст в исключении и желательно чтобы он был доступен в обработчике. Например так.
Код: Выделить всё
interface FriendlyExceptionInterface
{
public function getName(): string;
public function getSolution(): ?string;
public function getContext(): ?string;
}
Код: Выделить всё
class ErrorException extends \ErrorException implements FriendlyExceptionInterface
{
//...
private $context;
public function __construct($message = '', $context = null, $code = 0, $severity = 1, $filename = __FILE__, $lineno = __LINE__, \Exception $previous = null)
{
parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
$this->context = $context;
$this->addXDebugTraceToFatalIfAvailable();
}
public function getContext(): ?string
{
return $this->context;
}
//....
Тогда мы можем переписать UnknownCommandException так
Код: Выделить всё
lass UnknownCommandException extends ErrorException
{
//....
public function getSolution(): ?string
{
return $this->getSuggestedAlternatives();
}
protected function getSuggestedAlternatives()
{
//working with $this->context instead of $this->command
//...
}
}
Ну и обрабатывать так
Код: Выделить всё
try {
//execute commands
} catch (\ErrorExeption $e) {
$message = $e->getMessage();
if ($e instanceof FriendlyExceptionInterface) {
$name = $e->getName();
$solution = $e->getSolution();
$context = $e->getContext();
$message = "{$name}:{$message}\n{$solution}";
//use a custom solution
if (($e instanceof UnknownCommandException) && empty($solution)) {
$message .= "\n Command {$context} - ...custom solution...";
}
//custom action
if (($e instanceof BadPasswordException) && $context == 'account/send-money' ){
sendEmailToSecurity('Danger! Unauthorized money transfer has been detected!');
}
}
}
Re: Дружественные исключения
Добавлено: 2019.09.21, 19:07
samdark
Контекст именно для этого интерфейса не важен. Интерфейс не про то, как мы будем собирать вывод, а про то, что мы будем выводить. Выводим мы сообщение, трейс и подсказку-решение. Если для их формирования в конкретном исключении необходимо название текущей команды, то требуем его в конструкторе этого исключения:
Код: Выделить всё
class UnknownCommandException extends ErrorException
{
private $command;
public function __construct(string $command)
{
$this->command = $command;
parent::__construct('Unknown command '. $command);
}
public function getSolution(): ?string
{
$alternatives = $this->getSuggestedAlternatives();
if ($alternatives === []) {
return null;
}
return 'Did you mean one of"' . implode('", "', $alternatives) . '"?';
}
protected function getSuggestedAlternatives(): array
{
// working with $this->command
// ...
}
}
Re: Дружественные исключения
Добавлено: 2019.09.22, 09:55
yiiliveext
samdark писал(а): ↑2019.09.21, 19:07
Контекст именно для этого интерфейса не важен. Интерфейс не про то, как мы будем собирать вывод, а про то, что мы будем выводить. Выводим мы сообщение, трейс и подсказку-решение. Если для их формирования в конкретном исключении необходимо название текущей команды, то требуем его в конструкторе этого исключения:
Ок, пусть будет так. А почему бы не вынести в независимый пакет
https://github.com/yiisoft/yii-web/tree ... rorHandler целиком? Там вроде только одна зависимость фреймворка Yiisoft\Yii\Web\Info и этот момент решаем.
Re: Дружественные исключения
Добавлено: 2019.09.23, 00:26
samdark
Можно и вынести, конечно. Вы первый кто спросил.