Недавно я наткнулся на некоторый код, который использовал пользовательский обработчик ошибок, чтобы превратить любые ошибки 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
я сначала проверяю, является ли ошибка E_NOTICE
, и бросаю только в том случае, если это не так (я все равно регистрирую уведомление). .
Я бы изменил AppException
на что-то, что расширяет ErrorException
... Примерно так: PhpRuntimeErrorException расширяет ErrorException
, который вы ТОЛЬКО используете для ошибок PHP .. Причина в том, что оно более читабельно (легче определить, что такое PhpRuntimeErrorException
, без необходимости выяснять, где оно возникло). Другая причина заключается в том, что ErrorException
будет хранить информацию о генерирующей строке / файле / и т.д., где она не будет храниться где-либо еще (поскольку обратная трассировка начинается со строки 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 (более объектно-ориентированные) используют исключения для вещей, которые раньше могли бы вызывать ошибки, так что здесь есть некоторая серая зона.
Существует также класс ErrorException ядра PHP - http://www.php.net/manual/en/class.errorexception.php, который выглядит немного проще в использовании, чем ваш пример кода, если вы хотите пойти по этому пути.