Этот топик наглядно показал неумение спорящих выдерживать тему дискуссии. Обидно господа.
Что касается исключений. Может стоит сделать шаг назад и задать себе вопрос: "А можно ли вообще сравнивать традиционные методы обработки ошибок (характерные для функционального подхода) и исключительные ситуации (характерные для ООП)?". Думаю сравнивать можно, но не стоит забывать, что качество кода напрямую не зависит от используемого стиля разработки. Поэтому некорректно говорить, что "исключения нужны тем, кто не может/не хочет писать надежный код". Неужели автор не видел качественных ООП систем использующих механизм исключений?! Качественный и надежный код можно написать с использованием любого подхода. Вопрос совсем в другом. Вопрос в
себестоимости такого кода и стоимости его
сопровождения.
Сравнивая традиционный подход и исключения можно выделить несколько аспектов различающий эти подходы
1.
Место генерирования и место обработки ошибок. в традиционном случае обработка ошибки должна содержаться либо непосредственно в коде, который сгенерировал ошибку либо в функции, которая вызвала функцию генерирующую ошибку. Другими словами место генерирования и место обработки не может быть разделено более чем одним уровенем стека вызова. Я знаю, что фактически возможно и больше, но вы же не будете говорить, что это нормальный код или, тем более, приводить такой код на страницах этого форума. Берегите нервы окружающих.
В случае exceptions место генерирования и обработки может быть удалено друг от друга на более дальнее расстоние. whirlwind очень критично заметил что это не имеет смысла. Действительно чем дальше расположены эти две точки кода, тем менее эффективно мы можем обработать ошибку. Но нас ведь никто ни к чему не принуждает. Мы можем расположить обработку там, где ошибку можно обработать оптимально, а как показывает моя практика это "оптимально" является точкой кода на удалении 2х-3х уровней стека от точки генерирования ошибки.
А разделение места генерирования и обработки ошибки (более чем 1 уровнем стека) это основное преимущество, которе дают нам exceptions. Ведь в системном коде мы знаем что за ошибка произошла, но мы не знаем, как корректно ее обработать в
данной ситуации. Подчеркну, что в приложении могут быть правила обработки ошибок, которые зависят не только от типа ошибки, но и от других факторов. Скажем три раза пытаемся подключиться к серверу DB если нет, то переходим к следующему в списке (не такое уж надуманное правило, особенно для клиентских приложений).
2.
Информативность сообщения об ошибке
Как вам это:
Ну и что за ошибка тут произошла? Ну конечно, надо отдать должное, нормальный программист сделает так:
PHP:
return ERR_DB_CONNECT_FAILED;
Уже значительно лучше, но неужели вы будете спорить, что следующий код значительно информативней:
PHP:
throw new DbConnectFailedException($host, $reason);
Так как механизм исключений основан на объектной модели, то конкретный тип исключительной ситуации может быть заточен под конкретную ошибку и нести столько информации, сколько необходимо для корректного восстановления потока выполнения приложения.
3.
Объединение ошибк в группы
Тот внешний catch приложения (или просто exception handler), который так сильно критиковался whirlwind'ом, на самом деле играет очень важную роль. Он позволяет централизованно обрабатывать ошибки. Скажем все ошибки работы с БД мы должны записать в один лог, а ошибки валидации данных в другой лог, а на информацию о других ошибках отправить администратру по почте. В данном случае транспортировка кодов ошибок, вроде:
PHP:
ERR_DB_CONNECT_FAILED;
ERR_DB_CONNECT_REFUSED;
ERR_DB_ACCESS_DENIED;
до места обработки вызовет значительные затруднения. Более того, как мне определить в обработчике, что ERR_DB_CONNECT_REFUSED и ERR_DB_ACCESS_DENIED являются подтипами ERR_CONNECT_FAILED? Ведь обе ошибки (ERR_DB_CONNECT_REFUSED и ERR_DB_ACCESS_DENIED) относятся к ошибкам "отказа в соединении" (ERR_CONNECT_FAILED), и логика их обработки может быть одинаковая, а может быть и разная. Все зависит от требований к приложению. Безусловно это проблема решаемая с помощью своего собственного обработчика, который может организовывать коды ошибок в дерево для выявления групп и подгрупп.
Но согласитесь, нижеприведенный код приятнее и
понятнее
PHP:
class dbConnectionException extends exception{}
class accessDeniedDbException extends dbConnectionException{}
class connectRefusedDbException extends dbConnectionException{}
я уже не говорю об обработке
PHP:
... } catch ( dbException $e ) {
// Пишем в db.log
} catch ( validationException $e ) {
// Пишем в validation.log
} catch ( fooException $e ) {
// Отправляем писмо администратору
} catch ( Exception $e ) {
// Общие правила обработки
}
Этим постом я хотел показать, что нет нерешаемых задач в обоих методиках. И там и там код может быть качественным и надежным. Вопрос, как я уже сказал, в
стоимости. Поэтому "если вы
не любитель каждый раз изобретать велосипед и цените свой собственный труд", то думаю вы постараетесь оценить преимущества, которые предоставляет вам ООП и механизм исключений.