Недавно я натолкнулся на какой-то код, который использовал собственный обработчик ошибок, чтобы превратить любые ошибки PHP в исключение обобщенного приложения. Также был определен специальный обработчик исключений, который будет регистрировать исключение, если он находится в определенном диапазоне кода ошибки. Пример:
class AppException extends Exception { } function error_handler($errno, $errstr, $errfile, $errline) { throw new AppException($errstr, $errno); } function exception_handler($exception) { $min = ...; $max = ...; if ($exception->getCode() >= $min && $exception->getCode() <= $max) { // log exception } } set_error_handler('error_handler'); set_exception_handler('exception_handler'); $a[1]; // throws exception
Проблема в том, что я видел такие вещи, как:
try { do_something(); } catch (AppException $exception) { }
Это подразумевает отсутствие различий между фактическими ошибками программирования и «исключительным» поведением. После дальнейшего копания я наткнулся на части кода, которые были разработаны вокруг идеи о том, что ошибки PHP представляют собой «исключительное» поведение, такое как:
... function my_function($param1, $param2) { // do something great } try { my_function('only_one_param'); } catch (AppException $exception) { }
Который заканчивается запутыванием ошибок и дизайном интерфейса приложения.
Каково ваше мнение об обработке ошибок таким образом? Стоит ли превращать собственные ошибки PHP в исключения? Что вы делаете в ситуациях, подобных описанным выше, где создается кодовая база вокруг этой идеи?
Лично я делаю это все время. Единственное различие заключается в том, что в моей функции error_handler
я проверяю, error_handler
ли ошибка является E_NOTICE
, и только бросайте, если это не так (я регистрирую уведомление в любом случае) …
Я бы изменил AppException
на то, что расширяет ErrorException
… Что-то вроде: PhpRuntimeErrorException extends ErrorException
которое вы используете только для ошибок PHP … Причина в том, что это более читаемо (проще сказать, что PhpRuntimeErrorException
не нужно где его бросают). Другая причина заключается в том, что ErrorException
будет хранить информацию генерирующей строки / файла / etc, где она не будет храниться в другом месте (поскольку обратная трассировка начинается с линии throw
) …
Итак, вы можете «попробовать» код следующим образом:
try { $f = fopen('foo.bar', 'r'); $ret = ''; while ($data = fread($f)) { $ret .= process($data); } fclose($f); return ''; } catch (PHPRuntimeErrorException $e) { throw new RuntimeException('Could not open file'); } catch (ProcessException $e) { fclose($f); throw new RuntimeException('Could not process data'); } return $ret;
Я также создаю обработчик исключения по умолчанию, создающий страницу ошибок сервера 500. Это потому, что любые исключения должны быть пойманы, а если они не были, это действительно ошибка сервера …
Только мой опыт и мнение …
В сообществе PHP были некоторые споры об этом. Я считаю, что общее мышление состоит в том, что ошибки – это вещи, которые бросают внутренние функции PHP, и представляют собой проблемы с кодированием, которые вам действительно нужно исправить; в то время как исключения – это вещи, брошенные вашим кодом приложения, которые вам просто нужно «обрабатывать».
Однако некоторые из новых расширений SPL (которые, как правило, более объектно-ориентированные) используют исключения для вещей, которые ранее могут быть вызваны ошибками, поэтому существует некоторая серая область.
Существует также основной класс PHP ErrorException – http://www.php.net/manual/en/class.errorexception.php, который выглядит немного проще в использовании, чем пример вашего кода, если это маршрут, по которому вы хотите спуститься.
Я конвертирую все, включая уведомления об исключениях. Нет никаких оснований позволять исключениям продолжать нормально, как это происходит. Неопределенная переменная или смещение? Это проблема.