Обработка ошибок, часть 2. Разбор примера. Исключения.
Пример из жизни.Использование исключений.
Комментарии (12)
Пример из жизни.
Вот яркий образчик "обработки ошибок", который можно встретить практически в любом скрипте
if (is_writable($file) {
$handle = fopen($file,'w') || die('error opening');
fwrite($handle, $text) || die('error writing');
fclose($handle);
} else die("not writable");
Почему это неправильно, было рассказано в первой части.
Попробуем переписать этот код по-другому.
$handle = fopen($file,'w');
$written=fwrite($handle, $text);
fclose($handle);
if ($written===FALSE) {
$error="Извините, произошла ошибка. Попробуйте повторить позднее"
}
Функция is_writable имеет смысл только в том случае, если планируется как-то реагировать на невозможность записи. А если для пользователя, как это часто бывает, существует только два состояния - "операция прошла успешно" и "произошла ошибка", то и дополнительная проверка ничем не поможет. А вот запись в лог конкретной причины невозможности записи - очень поможет программисту.
поэтому мы убираем проверку is_writable, чтобы ошибки при открытии и записи файла пошли в лог, а для сообщения пользователю проверяем только самый конечный результат - запись в файл.
однако это решение подходит не для всех случаев. иногда от наличия ошибки зависят очень большие куски кода, которые гарантированно будут выдавать ошибки, которые ничего не добавят к самой первой. К примеру, если на месте fopen будет mysql_connect, за которым идет десяток запросов, то после нужной программисту ошибки соединения в логе будет еще куча ошибок запросов.
В таких случаях нужно обрабатывать эти "ключевые точки":
if ($handle = fopen($file,'w')) {
$written=fwrite($handle, $text);
fclose($handle);
}
if (!$handle OR $written===FALSE) {
show_error_page();
}
Смысл здесь в чем?
Как описано в первой части, мы должны разделять саму ошибку, сообщение об ошибке, информирование о ней пользователя и программиста.
саму ошибку обрабатывает первый if - если файл не открылся, то записи не будет.
сообщение об ошибке, как положено, не пойдет на экран, а пойдет в лог.
программист будет проинформирован из лога же.
А пользователь, которому неважно, какие у нас там были ошибки, а интересует только одно: записалось-не записалось - получает свое сообщение. Для этого мы проверяем то, что интересует пользователя - произошла ли, собственно, запись в файл.
Использование исключений.
В PHP5 появился стандартный для большинства языков механизм исключений.
почитать про него можно в документации, а здесь мы просто посмотрим, как будет выглядеть код с применением этого механизма:
try {
$handle=fopen($file,"a");
if (!$handle) throw new Exception("open");
fwrite($handle, $text);
fclose($handle);
}
catch (Exception $e) {
show_error_page();
}
Можно провести такую аналогию, что throw является аналогом die, но не для всего скрипта, а только для канарейки - кода, заключенного между try {}. Что позволяет, с одной стороны, не выполнять код, который все равно не сработает, а с другой - не обрывать работу всего скрипта, а завершить его корректно.
Вообще, механизм исключений предоставляет просто неограниченные возможности по управлению ошибками.
Взять, например, вот такой код:
function exceptions_error_handler($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler('exceptions_error_handler');
при его использовании наш тестовый пример становится совсем удивительным:
try {
$handle = fopen($file,'w');
fwrite($handle, $text);
fclose($handle);
}
catch (Exception $e) {
show_error_page();
}
Видишь обработку ошибок? И я нет. А она есть!
fwrite($handle, $text); не выполнится, если fopen отработала с ошибкой.
Правда, применять такой способ следует очень аккуратно, поскольку исключение будет вызвано не там, где мы точно его хотим, а вообще любой ошибкой, даже нотисом на несуществующую переменную.
Написать комментарий
Пожалуйста, воздержитесь от посылки спама.
Сообщения, содержащие гиперссылки, проходят премодерацию.