И держите их простыми

Пару дней назад я увидел этот YouTube Short с очень рекомендуемого канала YouTube, который показывает очень элегантный способ работы с вложенностью и повторением блоков try/catch в JavaScript, и я подумал, можно ли сделать что-то подобное для PHP.

Мы используем блоки try/catch в PHP, чтобы сделать наши программы отказоустойчивыми или обеспечить обработку ошибок до определенного момента. С помощью блоков try/catch мы можем изящно обрабатывать определенные ошибки, которые могут возникнуть во время выполнения, без обязательной остановки нашего приложения.

Обработка ошибок может включать предоставление обратной связи конечному пользователю, чтобы сообщить ему, что пошло не так, отправку данных о состоянии и отладке в службы ведения журналов для последующего дальнейшего анализа, исправление ошибки с использованием некоторых конфигураций по умолчанию или даже игнорирование ошибки без каких-либо действий вообще. .

Многие нативные функции PHP, сторонние библиотеки и фреймворки выдают определенные типы ошибок/исключений, если во время их выполнения происходит что-то неожиданное. В зависимости от типа ошибки, контекста выполнения и политик обработки ошибок, которые реализует каждое из них, могут быть выброшены различные конкретные типы исключений, и каждое из них может нуждаться в обработке определенным образом, что приводит к тому, что клиентский код выглядеть примерно так:

Представьте, что этот повторяющийся шаблон распространяется во многих других функциях или методах, он, безусловно, довольно многословен и громоздок для работы, и это делает код немного более сложным для понимания.

Шаблон

Инкапсулируя подверженный ошибкам код в команду, мы можем легко обернуть его обработчиком ошибок, который будет отвечать за обработку ошибок и работу с логикой try/catch:

Это комбинация паттернов проектирования команда, шаблонный метод и декоратор, что приводит к очень гибкому механизму обработки ошибок без распространения блоков try/catch на всю кодовую базу. Предоставляя различные реализации метода handleError, можно достичь различных уровней абстракции и гибкости, а также поддерживать различные подходы к обработке ошибок.

Примеры использования

В этом разделе я приведу несколько примеров использования, показывающих, как можно реализовать метод handleError для соответствия различным политикам и сценариям обработки ошибок, а также насколько гибким может быть этот шаблон. Я надеюсь, что это поможет вам понять, как работает этот шаблон, и даст читателям некоторую информацию, чтобы они могли подумать о дополнительных примерах и сценариях, где он может быть применим.

Пример №1: Обработка ошибок в самой обёртке

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

Пример №2: Использование накопителя ошибок

Часто при возникновении ошибки типа X поток выполнения и ответ конечному пользователю могут отличаться от тех, которые возникают при возникновении ошибки типа Y. Например, мы можем подумать, что на результат выполнения команды могут повлиять определенные типы произошедших ошибок.

Первый подход к поддержке этих сценариев — разрешить самой команде обрабатывать любые ошибки, возникающие во время ее выполнения. Второй, более сложный, будет иметь накопитель ошибок, который хранит текущее состояние программы в отношении интересующих ошибок и исключений:

Эта очень простая версия накопителя ошибок может быть более сложной, которая, помимо регистрации любых произошедших ошибок, отправляет журналы во внешнюю службу журналов, включает некоторый статус предупреждения на уровне программы или запускает некоторый фоновый процесс проверки работоспособности.

Пример №3: Состав обработчиков ошибок

Более сложная, но очень гибкая версия этого шаблона может быть достигнута путем объединения его с шаблоном проектирования цепочка ответственности, что позволяет нам настраивать нашу логику обработки ошибок, чтобы не привязывать ее к конкретной реализации. Взгляните на следующие фрагменты:

Этот последний пример демонстрирует очень гибкий подход. Я предоставляю реализацию по умолчанию как последнюю цепную сталь, которая ничего не делает с ошибками, которые не обрабатывались предыдущими сталями. Это можно изменить, чтобы вызывать исключения, которые не были обработаны, чтобы избежать сокрытия нежелательных ошибок за этой логикой отсутствия отчетов.

Кроме того, гибкий подкласс обработчика ошибок, который использует два определяемых клиентом обратных вызова PHP для оценки метода canHandle и выполнения обработки ошибок, также может быть создан как подкласс ErrorHandler. Это позволит вам создать собственный обработчик ошибок «на лету», просто определив его с помощью обратных вызовов.

Это всего лишь несколько основных примеров, которые я привел, чтобы проиллюстрировать, как можно использовать этот шаблон. Из этой отправной точки может появиться больше хороших идей и причудливых дизайнов, которые могут помочь вам справиться с распространением блоков try/catch.

Как вы, возможно, заметили, комбинируя шаблоны проектирования, мы получаем очень богатые, мощные и гибкие решения, поэтому я призываю вас делать это, но всегда помните о том, чтобы не переусердствовать с вещами, которые можно решить с помощью более простых подходов.