Поэтому очень важно уметь корректно выявлять и обрабатывать ошибки, которые могут возникнуть в скрипте. Для этого в PHP предусмотрено два механизма - обработка ошибок и обработка исключений.
С точки зрения разработчика, основное отличие ошибки от исключения в том, что после возникновения ошибки скрипт может продолжить выполнение, а после возникновения исключения - нет.
Ещё одно различие - для обработки исключений необходимо использовать функции и специализированные языковые конструкции, а для обработки ошибок - только функции.
Исключения - это какие-либо аварийные ситуации, возникающие при выполнении скрипта. В PHP исключение можно сгенерировать ("выбросить", "вызвать") и поймать его. Исключение может сенерироваться как интерпретатором, так и разработчиком.
Вызов исключения производится следующим образом:
<?php
throw new Exception('My exception message');
?>
Перехват исключения осуществляется с помощью конструкции try...catch. В общем виде эта конструкция записывается так:
<?php
try {
// код, который может выбросить исключение
} catch(Exception $ex) {
//$ex - экземпляр класса Exception
// или его наследника
}
?>
Стоит отметить, что блоков catch может быть много, по одному на каждый класс перехватываемых исключений. Таким образом можно создать фильтр исключений, т.е. перехватывать не все, а только избранные типы исключений, а все остальные будут перехвачены стандартным обработчиком PHP.
При необходимости можно создать собственный класс обработки искоючений, унаследовав его от класса Exception. Собственный класс обработки исключений - это удобный инструмент разработчика, дающий возможность вести логи, отображать сообщения об ошибках, менять ход выполнения скрипта и много других возможностей.
Законный вопрос - зачем самому вызывать ошибку? Рассмотрим простой пример - есть функция формирования отчёта о деятельности компании. Эта функция содержит несколько сотен строк кода, вызывает ещё десяток функций и читает данные из баз данных и файлов. Теперь представим ситуацию, когда одна из баз данных вдруг отключилась, а мы об этом узнали лишь в середине процедуры. Раз нет данных, то и формировать отчёт нет смысла - он будет неполным и некорректным. Но как прервать выполнение основной функции, одновременно сообщив подробности ошибки? Можно сделать с помощью нескольких if..else, но более простым решением будет использование исключений.
<?php
// Класс для записи в лог-файл тех исключений,
// которые не требуют моментальной реакции администратора
class ExceptionWriter extends Exception
{
publuc void Write()
{
// записываем содержимое ошибки в лог-файл
}
}
// Класс для отправки на email всех исключений,
// о которых администратор должен узнать немедленно
class ExceptionMailer extends Exception
{
publuc void Send()
{
// отсылаем содержимое ошибки на email админа
}
}
try
{
//...
// код подключения необходимых данных
//...
if(!$connected)
trow new ExceptionMailer('Источники данных не подключены!');
//...
// код обработки данных
//...
if(!$template_present)
trow new ExceptionWriter('Файл шаблона не найден.');
//...
// код обработки шаблона и генерации отчёта
//...
}
catch(ExceptionWriter $ew)
{
$ew->Write();
}
catch(ExceptionMailer $em)
{
$em->Send();
}
catch(Exception $ex)
{
echo 'Исключение: ' . $ex->getMessage();
}
?>
В этом примере мы объявляем два наследника от класса Exception и выполняем генерацию отчёта. Первым делом мы подключаем все нужные источники данных (базы данных, файлы и пр). Если хотя бы один источник не подключился - продолжать работу нельзя и нужно предупредить администратора об ошибке. Поэтому генерируем исключение типа ExceptionMailer. Если подключение прошло успешно - продолжаем работу, обрабатываем данные и генерируем отчёт на основе шаблона. Если шаблон не найден - генерируем соответствующее исключение.
В рассмотренном примере важную роль играет порядок catch, точнее порядок проверки на тип исключения. Если первым поставить Exception, то все остальные исключения никогда не сработают, т.к. конструкция catch(Exception $ex) перехватывает абсолютно все доступные исключения.
PHP позволяет использовать свой обработчик исключений. Для этого необходимо объявить собственную функцию обработки и зарегистрировать её при помощи функции set_exception_handler().
<?php
function special_handler($exception) {
echo "log: " . $exception->getMessage() . "\n";
}
set_exception_handler('special_handler');
throw new Exception('Пример исключения');
?>
После этого все возникающие исключения, не обрамлённые конструкцией try...except, будут передаваться в объявленную вами функцию. Например, можно изменить функцию, чтобы она писала все исключения в файл и выдавала пользователю в браузер "красивое" сообщение об ошибке сервера:
<?php
function special_handler($exception) {
// добавляем описание исключения в лог-файл
$file = fopen("logfile.log", "a+");
fwrite($file, $exception->getMessage() . "\n");
fclose($file);
// выводим пользовалелю понятное сообщение
echo "Обнаружена ошибка сервера. Попробуйте ".
"войти позже. Приносим свои извинения.";
}
?>
Иногда эта функция бывает очень удобной, особенно в процессе отладки скриптов непосредственно на сервере. Если выводить исключения как обычно в браузер - их смогут увидеть посетители, а это не прибавит популярности вашему сайту. Гораздо менее болезненно пользователи воспримут сообщение типа "Извините, сервер находится на обслуживании, попробуйте войти позже.". Поэтому все ошибки и исключения необходимо писать в файлы, а лучше ещё и отправлять администратору на email.
Хорошим тоном при создании сайтов считается полное отсутствие ошибок. Если же ошибки возникают - они должны быть обработаны и представлены пользователю и разработчику в понятном виде.
Оригинал статьи на on-line-teaching