Обработка множества исключений: решение

Немного позже, чем думал (что простительно, ибо дни выдались хлопотные) привожу свои варианты решения упражнения, которое я озвучил в предыдущем посте. Условие повторять не буду, по приведенной ссылке все описано.

Решение 1, читерское.

В условии было сказано, что надо обрабатывать исключения в методах init(), run() и shutdown(). И хотя это явно не оговаривалось, по логике функционирования эти методы вызываются подряд. Следовательно, можно сделать так:

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

Достоинства решения:

  • простота;
  • минимум дублирования кода;
  • локальность модификации кода.

Недостатки:

  • жестко привязываемся к сценарию последовательного вызова методов init(), run(), shutdown(), в реальной жизни может потребоваться вызывать их из разных частей приложения в разные моменты времени;
  • метод-обработчик исключений должен очень многое знать обо всех возможных исключениях, при появлении нового исключения придется править метод-обработчик.

Решение 2, логичное.

Следующее решение приходит в голову практически сразу после прочтения условия, и оно действительно хорошо подходит для решения задачи.

Именно его в комментариях предложил Vladimir Rusinov, за что ему спасибо:

Достоинства решения:

  • простота,
  • независимость от мест вызова методов (то есть, их не обязательно вызывать подряд),
  • минимум дублирования кода,
  • локальность правок.

Недостатки решения:

  • метод-обработчик исключений должен очень многое знать обо всех возможных исключениях, при появлении нового исключения придется править метод-обработчик,
  • требуется дополнительная логика для прерывания обработки, если упадет init(), либо проброс исключения дальше.

Решение 3, хитрое.

Это решение в конечном итоге я и использовал в своем проекте. Сначала я приведу код, а потом дам дополнительные комментарии:

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

В PHP все исключения имеют по умолчанию два поля (есть и другие, но они нас не интересуют): $message = null и $code = 0, сообщение и код ошибки соответственно. Во всех наших исключениях мы переопределяем значение по умолчанию для кода ошибки, чтобы оно соответствовало типу исключения.

Теперь, когда мы создаем исключение, мы можем задать ему сообщение, которое описывает причину его возникновения, и, если надо, можем уточнить и код ошибки. Если же мы сообщение вручную не зададим - оно будет получено через класс Errors. В случае, если мы поймаем "не наше" исключение (типа простого Exception), у него код ошибки будет 0, и класс Errors успешно опишет его как "Unknown exception".

Достоинства решения:

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

Недостатки решения

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

Итоги

Я привел целых три решения задачи и видно, что ни одно из них не является безоговорочно правильным. А это значит, что даже такая простая задача, как описано в этом упражнении, требует внимательного анализа требований к системе и ваших возможностей, как ее разработчика. В моем случае решение 3 оказалось наименьшим злом, и я использовал его. Но запросто может оказаться, что в другой ситуации оптимально "наивное" решение 1.

Beto Vazquez Infinity-The Laws Of The Future



Trackback URL for this post:

/trackback/415


Отправить комментарий

CAPTCHA
Вы точно не бот?
7 + 1 =
Without JavaScript you won't pass captcha test, sorry. Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.