Хорошая ли практика создавать свои классы 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й? На сколько это хорошая практика? Или я не правильно понял механизм работы исключений?

update: И как быть, если у меня возникает несколько исключений, и я хочу выдать пользователю информацию о всех возникших сразу?
  • Вопрос задан
  • 2206 просмотров
Решения вопроса 2
@galliard
Практика хорошая. Именно так и стоит делать. В идеале у каждой ошибки должен быть свой уникальный эксепшн. Например, от FileException можно наследовать например NotFoundFileException и AccessFileException. При этом тело классов в большинстве случаев будет пустым.

А вот то, что ты пытаешься поймать все возможные эксапшны в контроллере - это совсем не хорошо. По хорошему нужен отдельный эксепшн хендлер для этого.
Ответ написан
@WhoMe
UPD:
> Это нормально что в контроллере столько много catch'eй?
Не то чтобы нет, но "попахивает".
> как быть, если у меня возникает несколько исключений, и я хочу выдать пользователю информацию о всех возникших сразу

У вас смешана валидация входных параметров с возникновением нештатных ситуаций.
Exception стоит кидать если метод не может вернуть осмысленный результат.
Ошибки валидации ("сообщение слишком длинное", "файл не того расширения") можно собирать, к примеру, в массив. Как валидировать входные данные выходит за рамки этого вопроса.
------
> Можно ли так делать?
Попробуйте использовать правило 5 почему (ну или "зачем") чтобы попытаться добраться до сути.

- Я даю отдельные имена исключениям.
- Зачем?
- Для того что бы отловить различные ошибки.
- Зачем отлавливать различные типы ошибок?
- Чтобы показывать разные сообщения.
- Зачем показывать разные сообщения?
- Чтобы пользователь мог отреагировать определенным образом на конкретный тип ошибки
(решить что ему делать в случае конкретного исключения).

Давайте посмотрим что человек (пользователь) на вашем сайте (системе) может сделать в случае ошибки:
1. Не корректное сообщение.
Привести его к корректному (сделать его короче, как-то отформатировать и т.п.)

2. Не удалось загрузить файл.
Если файл слишком большой - можно попробовать загрузить файл поменьше.
Если это внутренняя ошибка (например: закончилось место на диске на сервере, нет прав на запись и т.п) - то ничего, здесь уже требуется вмешательство тех кто обслуживает систему.

3. Ошибка PDO.
Ничего, это внутренняя ошибка.

Т.е. есть смысл создавать новый тип исключения, если пользователь системы может иначе отреагировать на этот тип.

Я использую 2 типа исключений на уровне web-слоя: внешние и внутренние.
Внешние - если пользователь может повлиять на них (страница не найдена, файл слишком большой, нет доступа и т.п.).
В них сообщение показывается пользователю как есть. Подноготная (пути к файлам, пароли, названия БД и т.п) в такие ошибки не вкладывается.

Внутренние - пользователь не может влиять (ошибка подключения к БД, SQL syntax error и т.п).
Пользователю показывается только код ошибки. В такие ошибки также вкладываю техническую информацию.

Ты (как программист) также можешь быть пользователем какой-то системы (к примеру, библиотеки).
Например, библиотеки для работы с БД.
Предположим ты импортируешь csv-файл в базу, заполняешь числовую колонку и вместо числа у тебя попадается текст.
Запрос падает с ошибкой и тебе не плохо бы отличать её от ошибки синтаксиса.
Если попался текст вместо числа - то можно просто пропустить строку.
Если ошибка синтаксиса - то у ошибка в коде и продолжать импорт нет смысла.

Подытожу:

> Можно ли создавать свои пустые классы Exception'ов наследуемые от класса Exception только лишь для того что бы было отдельное имя исключения?

Можно.

Сколько делать отдельных исключений?
Зависит от того как их будет обрабатывать пользователь.
Если твой контроллер(модель, подсистема) кидает множество разных ошибок и все они обрабатываются одинаково - то стоит призадуматься.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
php10
@php10
Разработчик на PHP
Во фреймворках так и делают. Я в своей практике использую несколько исключений. Так что это нормально. Почитайте еще про интерфейс \Throwable, который появился в PHP 7
Ответ написан
Комментировать
Имеет смысл, например, для внутренних эксепшенов в библиотеках.
Потому что библиотека используется как черный ящик.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы