HTML, Excel, Word, SEOPHP курс для чайников ⇒ Обработка исключений

PHP для "чайников"

Инструменты
Выбираем IDE
Выбираем Web-сервер
Выбираем СУБД
Структура языка PHP
Первый шаг
Синтаксис
Типы данных
Переменные и константы
Операторы
Выражения
Управляющие структуры
Функции
Классы
Исключения
Ошибки
Массивы
Глобальные массивы
Cookies
Сессии
Загрузка файлов
Работа с файлами
Работа с файлами на диске
Работа с данными в файле
Пример управления файлами
Работа с базами данных
Подключение
Анализ результатов
Выполнение запросов
Отключение
Пример: отслеживание пользователей
Работа в сети
Отправка почты
Безопасность
HTTP-аутентификация
Защита логином и паролем
Автоматизация
Регулярные выражения в PHP
Интеграция
PHP и JavaScript

 

PHP: Обработка исключений


Автор: Артемьев Сергей Игоревич
ICQ: 438856621
email: _spin_@bk.ru

Все пользователи Сети знают, как порой неприятно открывать страницу и видеть вместо долгожданной статьи/блога/картинки некий маловразумительный текст, сообщающий об ошибке сервера. К сожалению, реальность Интернет такова, что очень сложно сделать скрипт, одинаково хорошо работающий на любой платформе и при любых настройках сервера.


Поэтому очень важно уметь корректно выявлять и обрабатывать ошибки, которые могут возникнуть в скрипте. Для этого в 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.

Хорошим тоном при создании сайтов считается полное отсутствие ошибок. Если же ошибки возникают - они должны быть обработаны и представлены пользователю и разработчику в понятном виде.



В начало страницы



В начало страницы