Страницы

Поиск по вопросам

понедельник, 15 апреля 2019 г.

Хорошая ли практика создавать свои классы Exception для отлавливания разных ошибок?

Я только недавно изучил механизм Exception'ов и сейчас их осваиваю. Вот пара вопросов по поводу их применения:
Можно ли создавать свои пустые классы Exception'ов наследуемые от класса Exception только лишь для того что бы было отдельное имя исключения? Например: я работаю с файлами, и если файл не удалось загрузить файл - я бросаю исключение
throw new FileException('Не удалось загрузить файл')
Сам класс `FileException ничего не содержит
class FileException extends \Exception { //empty! }
И второй вопрос, который вытекает из первого. Делаю я это для того что бы отловить различные ошибки. Например при добавлении сообщения на сайте, у меня может возникнуть разные исключения, например: Не корректное сообщение, Не удалось загрузить файл, ошибка PDO. То есть в контроллере это будет выглядеть так:
public function actionMethod() { try { //some code; } catch (FileException $e) { echo 'С файлами что то пошло не так:' . $e->getMessage(); } catch (MessageException $e) { echo 'С сообщением что то пошло не так:' . $e->getMessage(); } catch (PDOException $e) { echo 'С БД что то пошло не так:' . $e->getMessage(); } catch (Exception $e) { echo 'Что то совсем пошло не так :('; } }
Можно ли так делать? Это нормально что в контроллере столько много catch'eй? На сколько это хорошая практика? Или я не правильно понял механизм работы исключений?


Ответ

Нужны ли исключения для каждой ошибки отдельно?
Отвечая на вопрос
При добавлении сообщения на сайте, у меня может возникнуть разные исключения: Не корректное сообщение, Не удалось загрузить файл, ошибка PDO. Нужны ли исключения для каждой ошибки отдельно?
Нужно исходить из следующего:
что даст текст исключения для пользователя что даст разработчику
Не корректное сообщение Не удалось загрузить файл
Это стоит отдать в браузер, чтобы пользователь понял свою ошибку и исправил ее. Старайтесь сделать такое сообщение понятным. "Не удалось загрузить файл. Используйте разрешенные форматы (docx, xlsx)"
ошибка PDO
Особенности работы сайта пользователю знать не нужно. Запишите себе в журнал, и сообщите "Ошибка сервера, попробуйте чуть позже". Может видели сообщения у Гугла и Яндекса а-ля "что-то сломалось, но мы уже знаем".
// глобальный отлов ошибок try {
try { throw new Exception("DB error"); } catch (Exception $e) { // Я люблю в качестве кодов ошибок использовать 400-е и 500-е HTTP коды $errCode = $e->getCode() if($errCode >= 500) { syslog(LOG_ERR, '[Sign][docs.list][error]MySQL is gone away'); http_response_code($errCode); throw new Exception("Ошибка сервера, попробуйте чуть позже"); } }
} catch (Exception $e) { // выводим ошибку пользователю }
Кстати, писать можно в syslog, его PHP-программисты почему-то незаслуженно забыли. А если к сислогу прикрутить что-то типа ELK, то можно отслеживать динамику ошибок и настроить уведомления.
Удобно, если ошибка произошла где-то в глубине
Если в каком-то глубоко вложенном методе что-то пошло не так, то бросить исключение - как экстренное всплытие. Это лучше, чем назад по цепочке возвращать null/false. Ваш код станет чище.
Использование исключений как способ построения логики вместо if ... else ...
Пример:
try { // пробуем получить координаты по картам Гугла $this->geoPositionGoogle($data); } catch (Exception $e) { // если не получилось, пробуем по картам Яндекса $this->geoPositionYandex($data); }
Защитное программирование
Его суть - в проверке пришедшего и ожидаемого значений. Я использую чаще всего в двух случаях:
много потенциальных точек возникновения ошибок. У меня это электронная подпись документов (может отказать сеть, база, скрипт подписания, и так далее). Подробный отчет об ошибках значительно облегчает диагностику проблем взаимодействие с внешними сервисами, где что-то может измениться без ведома программиста
Пример обмена с 1С:
switch($row['SECTION_TYPE']) { case 'directionBonus': // Ожидается, что название будет начинаться со слова "Бонус" if(!preg_match('~^Бонус\s+(.*)$~i', $row['SECTION_NAME'], $m)) throw new Exception("Wrong name"); break; case 'groupDDP'; // Ожидается, что название будет начинаться с кода раздела if(!preg_match('~^([0-9]+\.[0-9]+\.[0-9]+)\s+(.*)$~i', $row['SECTION_NAME'], $m)) throw new Exception("Wrong name"); break; default: // Ожидается, что других вариантов нет throw new Exception("No such case"); }
Хорошая ли практика создавать свои классы Exception для отлавливания разных ошибок?
Хорошая, но не увлекайтесь. Делайте минимум. Если будет больше, начнете путаться и зависать, решая, какое исключение больше подходит.
Хорошая статья

Комментариев нет:

Отправить комментарий