Я только недавно изучил механизм 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 для отлавливания разных ошибок?
Хорошая, но не увлекайтесь. Делайте минимум. Если будет больше, начнете путаться и зависать, решая, какое исключение больше подходит.
Хорошая статья
Комментариев нет:
Отправить комментарий