#php #исключения
Я только недавно изучил механизм 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й? На сколько это хорошая практика? Или я не правильно понял механизм работы исключений?
Ответы
Ответ 1
Нужны ли исключения для каждой ошибки отдельно? Отвечая на вопрос При добавлении сообщения на сайте, у меня может возникнуть разные исключения: Не корректное сообщение, Не удалось загрузить файл, ошибка 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 для отлавливания разных ошибок? Хорошая, но не увлекайтесь. Делайте минимум. Если будет больше, начнете путаться и зависать, решая, какое исключение больше подходит. Хорошая статьяОтвет 2
В принципе всегда есть соблазн расписать иерархию исключений - выглядит круто и радует глаз. Но как показывает опыт (лично мой, во всяком случае), дело это достаточно бессмысленное. Ввести хотя бы один свой класс имеет смысл, потому что часто желательно отличать свои исключения от стандартных. Еще один класс бывает нужен для нефатальных исключений, когда нужно выдать пользователю локализованное сообщение и продолжить работу. Вот в принципе и все, даже для больших проектов этой пары бывает достаточно. Но в общем я бы посоветовал поступать просто - вводите новый класс исключений только тогда, когда чувствуете, что он вам действительно необходим. И еще: catch для всех мыслимых видов исключений - ситуация ненормальная, разделяйте исключения только когда это принципиально. Для того ведь иерархия и строится.
Комментариев нет:
Отправить комментарий