Похоже нашел некоторый удобный способ их применять. Опишу здесь, если кому пригодится.
Во первых там стандарт есть какой-то PSR где есть 8 классов "опасности" ошибок. Но когда я вижу классификацию на 8 типов, то выглядит это как "на всякий случай сделаем" - человек не способен делить что-то на 8 типов, он в голове держит не более 7 вещей (и это очень прокачанный - 7 вещей). Определить - какая именно из 8 типов ошибка та, которая сейчас пришла в голову для меня - невозможно. Может кто-нибудь в книжке написал, но в жизни думаю он так не делает.
Если ошибки можно поделить на 8 степеней, то речь здесь не в степенях а в приоритете. То есть \SplPriorityQueue с цифрой приоритета, который в случае чего можно всегда поменять, и посмотреть разницу в статистике за период времени. В данном случае 8 типов означают что-то вроде цветовых маркеров на производстве - "откройте красный ящик, переложите вещи в синий ящик", только без раскраски, но в общем случае 8 для однозначного определения - слишком много, а для статистики - достаточно, хотя в то же время и нет.
Делим возникающие косяки на:
1. уведомление разработчика, что программа кривая и так не должно было быть
2. уведомление/перенаправление пользователя
3. оповещение других модулей в соседних папках о том, что случилось что-то, что они могли бы решить, но в одиночку никак
В
первую группу в основном падают стандартные эксепшены. Пишем мы функцию
function a() : int
{
return 'vasia';
}
Функия возвращает не то, что просили. Об этом должен узнать разработчик, который делает на базе вашего кода. Программа не должна запуститься. Удобный способ делать такие проверки, писать следующий код:
function verifyEmail($email) : ? string
{
if (filter_var($email, FILTER_VALIDATE_EMAIL)) return null;
return __FUNCTION__ . ' fails: ' . $email;
}
// ... code
if ($err = verifyEmail(123)) throw new \UnexpectedValueException($err);
Мы возвращаем текст ошибки если проверка не прошла, валидируем.
Так, например, можно сделать проверку входных параметров на собственный тип не занимаясь ООП ересью на зашивание проверки в конструктор и разбивание массива на свойства, каждое из которых сеттер с валидатором и тд. минус файл и куча логики. Эти ошибки бывают что требуют вывода дополнительной информации в трейс. А поскольку эксепшен не принимает данные дополнительным параметром, я рекомендую дописать функционал `public function data(array $data))` и в особых случаях вызывать throw (new MyException($err))->data($data); и тогда в логах можно добавить эту самую $data не прибегая к танцем с бубном. Она врядли понадобится системному администратору или девопсу, но она точно понадобится тому, кто пойдёт ошибку править. Опять же - в эксепшене есть дерево вызовов и там есть аргументы. Но пару раз по причинам мне непонятным - пыха оставляет там не всё, что я ожидаю там прочитать. В той же валидации аргументом прилетает одна строка, если вывести все дерево - лог будет слишком огромный. А если одну строку - то это ничего не скажет. Чтобы понять, почему валидация сломалась часто нужно увидеть весь входной словарь данных.
Во
вторую группу я отнес ошибки HTTP приложения, приложения как штуки способной принимать команды и отвечать на них. Это разные редиректы. Это 500ые коды сделанные вручную. Это отсутствие прав доступа. Всё что по-любому закончится HTTPException или RedirectBack. Программа запуститься, но ошибка может быть вызвана тем, что во внешних условиях что-то идёт не так - нет прав доступа, или этот кусок программы сейчас отключен. То есть это не косяк кода, а сознательно установленный запрет. Эти ошибки чаще всего нужно переводить на другой язык или писать заглушку. Эти ошибки как правило бросаются фреймворком или приложением, и имеют либо неймспейс как у фреймворка, либо что-нибудь вроде \App\HttpException;
В
третью группу я отнёс ошибки, которые требуют внешних зависимостей. Насчет этой группы я пока не уверен, может быть это из-за того что я неправильно разобрался с первыми двумя. Предположим у нас есть модуль авторизации пользователя и есть модуль для работы с JWT-токенами. Вот когда модуль не смог разобрать JWT токен - он должен кинуть ошибку "я отработал и решил, что что-то пошло не так, но дальше - не моя забота". JWT разбор выполняет очень узкую задачу - парсинг токена. Туда не всунешь зависимостью модуль авторизации, это как поставить директора в подчинение работнику. Можно попробовать НЕ-бросать эту ошибку путем того, что инициировать проверку токена в модуле Авторизации, чтобы прямо там её и обработать. Но это странно, потому что Авторизация может быть сделана десятью путями и каждый из них зависимостью хардкодить - не очень хорошо. Именно эти ошибки должны иметь неймспейс, потому что их будут ловить и с ними работать, пытаясь их заглушить. То есть на уровне модуля - это критическая ошибка. А на уровне программы - это предупреждение.
На текущий момент мне кажется это правильным подходом. Если найду что-то ещё исправлю.