ПЕРЕХВАТ ОШИБОК. МЕТОД РЕГИСТРАЦИИ ОБРАБОТЧИКА ОШИБОК
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

 

В РНР версии 5 существуют два метода перехвата ошибок во время выполнения программы:

● регистрация обработчика ошибки.

● исключений;

РНР поддерживает средства, позволяющие "перехватывать" момент возникновения той или иной ошибки (или предупреждения) и вызывать при этом функцию, написанную пользователем.

Метод перехвата ошибок при помощи пользовательских функций далек от совершенства. Сделать с сообщением что-либо разумное, кроме как записать его куда-нибудь и завершить программу (при необходимости), не представляется возможным.

Метод исключений, который рассмотрен в п. 3, лишен этого недостатка, он достаточно сложен и практически не реализован на уровне стандартных функций РНР.

Пример использования обработчика ошибок приведен в листинге 2.1.

Листинг 2.1. Файл handler1.php

<?php ## Перехват ошибок и предупреждений.

// Определяем новую функцию-обработчик.

function myErrorHandler($errno, $msg, $file, $line) {

 // Если используется @, ничего не делать.

 if (error_reporting() == 0) return;

 // Иначе - выводим сообщение.

 echo '<div style="border-style:inset; border-width:2">';

 echo "Произошла ошибка с кодом <b>$errno</b>!<br>";

 echo "Файл: <tt>$file</tt>, строка $line.<br>";

 echo "Текст ошибки: <i>$msg</i>";

 echo "</div>";

}

// Регистрируем ее для всех типов ошибок.

set_error_handler("myErrorHandler", E_ALL);

// Вызываем функцию для несуществующего файла, чтобы

// сгенерировать предупреждение, которое будет перехвачено.

filemtime("spoon");

?>

Что бы ни произошло, программа всегда продолжает свою работу — просто в момент возникновения ошибочной ситуации вызывается функция-обработчик, а затем выполнение идет дальше. Именно по этой причине обработчик нельзя назвать кодом восстановления.

 

2.1 ФУНКЦИЯ set_error_handler

 

Функция

string set_error_handler(string $runcName [, int $errorTypes])

регистрирует пользовательский обработчик ошибок — функцию, которая будет вызвана при возникновении сообщений, указанных в $errorTypes типов (битовая маска, например, E_ALL ~ E_NOTICE).

Сообщения, не соответствующие маске $errorTypes, будут в любом случае обрабатываться встроенными средствами РНР, а не предыдущей установленной функцией-перехватчиком. Имя пользовательской функции передается в параметре $runcName. Если до этого был установлен какой-то другой обработчик, функция вернет его имя — с тем, чтобы его можно было позже восстановить. Пользовательский обработчик должен задаваться так, как показано в листинге 2.2.

Листинг 2.2. Файл handler0.php

<?php ## Перехват ошибок и предупреждений.

// Определяем новую функцию-обработчик.

function myErrorHandler($errno, $msg, $file, $line) {

 echo '<div style="border-style:inset; border-width:2">';

 echo "Произошла ошибка с кодом <b>$errno</b>!<br>";

 echo "Файл: <tt>$file</tt>, строка $line.<br>";

 echo "Текст ошибки: <i>$msg</i>";

 echo "</div>";

}

// Регистрируем ее для всех типов ошибок.

set_error_handler("myErrorHandler", E_ALL);

// Вызываем функцию для несуществующего файла, чтобы

// сгенерировать предупреждение, которое будет перехвачено.

filemtime("spoon");

?>

Теперь при возникновении любой ошибки или даже предупреждения в программе будет вызвана функция myErrorHandier(). Ее аргументы получат значения, соответственно, номера ошибки, текста ошибки, имени файла и номера строки, в которой было сгенерировано сообщение.

К сожалению, не все типы ошибок могут быть перехвачены таким образом. Например, ошибки трансляции во внутреннее представление E_PARSE, а также E_ERROR немедленно завершают работу программы. Вызовы функции die()также не перехватываются.

Назначить функцию реакции на E_PARSE и E_ERROR все же можно. Дело в том, что перехватчик выходного потока скрипта, устанавливаемый функцией ob__start(), обязательно вызывается при завершении работы программы, в том числе в случае фатальной ошибки. Конечно, ему не передается сообщение об ошибке и ее код; он должен сам получить эти данные из "хвоста" выходного потока (например, используя функции для работы с регулярными выражениями).

В случае если пользовательский обработчик возвращает значение false (и только его!), считается, что ошибка не была обработана, и управление передается стандартному обработчику РНР (обычно он выводит текст ошибки в браузер). Все остальные возвращаемые значения (включая даже null или, что то же самое, в случае, если оператора return вообще нет), приводят к подавлению запуска стандартной процедуры обработки ошибок.

 

2.2 ФУНКЦИЯ restore_error_handler()

 

void restore_error_handler()

Когда вызывается функция set_error_handler(), предыдущее имя пользовательской функции запоминается в специальном внутреннем стеке РНР. Чтобы извлечь это имя и тут же его установить в качестве обработчика, применяется функция restore_error_handler().Пример:

// Регистрируем обработчик для всех типов ошибок.

set_error_handler("myErrorHandler", E_ALL);

// Включаем подозрительный файл.

include "suspicious_file.php";

// Восстанавливаем предыдущий обработчик.

restore_error_handler();

Необходимо следить, чтобы количество вызовов restore_error_handler() было в точности равно числу вызовов set_error_handler().Нельзя восстановить то, чего нет.

 

2.3 ПРОБЛЕМЫ С ОПЕРАТОРОМ @

 

Пользовательская функция перехвата ошибок вызывается вне зависимости от того, был ли использован оператор подавления ошибок в момент генерации предупреждения. Это очень неудобно: поставив оператор @ перед вызовом filemtime(), мы увидим, что результат работы скрипта нисколько не изменился: текст предупреждения по-прежнему выводится в браузер.

Для того чтобы решить проблему, воспользуемся полезным свойством оператора @: на время своего выполнения он устанавливает error_reporting, равным нулю. Значит, мы можем определить, был ли вызван оператор @ в момент "срабатывания" обработчика, по нулевому значению функции error_reporting() (при вызове без параметров она возвращает текущий уровень ошибок) — листинг 2.3.

Листинг 2.3. Файл handler.php

<?php ## Перехват ошибок и предупреждений.

// Определяем новую функцию-обработчик.

function myErrorHandler($errno, $msg, $file, $line) {

 // Если используется @, ничего не делать.

 if (error_reporting() == 0) return;

 // Иначе - выводим сообщение.

 echo '<div style="border-style:inset; border-width:2">';

 echo "Произошла ошибка с кодом <b>$errno</b>!<br>";

 echo "Файл: <tt>$file</tt>, строка $line.<br>";

 echo "Текст ошибки: <i>$msg</i>";

 echo "</div>";

}

// Регистрируем ее для всех типов ошибок.

set_error_handler("myErrorHandler", E_ALL);

// Вызываем функцию для несуществующего файла, чтобы

// сгенерировать предупреждение, которое будет перехвачено.

@filemtime("spoon");

?>

Теперь все работает корректно: предупреждение не отображается в браузере, т. к. применен оператор @.



ГЕНЕРАЦИЯ ОШИБОК

 

Функция

void trigger_error(string $message [, int $type])

предназначена для искусственной генерации сообщения об ошибки с указанным типом. В РНР существует несколько констант, чьи имена начинаются с E_USER_, которые можно использовать наравне с E_ERROR, E_WARNING и т. д., но только для персональных нужд. Именно с функцией trigger_error() они чаще всего и применяются. Вот эти константы:

E_ERROR

E_WARNING

E_USER_NOTICE

Как их использовать — целиком зависит от программиста: никаких ограничений не налагается.

int error_log(string $msg [,int $type=O] [,string $dest] [, string $extra_headers])

Выше мы рассматривали директивы log_errors и error_log, которые заставляют РНР записывать диагностические сообщения в файл, а не только выводить их в браузер. Функция error_log по своему смыслу похожа на trigger_error(), однако, она заставляет интерпретатор записать некоторый текст ($msg) в файл журнала (при нулевом $type и по умолчанию), заданный в директиве error_log. Основные значения аргумента $type, которые может принимать функция, перечислены ниже:

● $type = = 0

Записывает сообщение в системный файл журнала или в файл, заданный в директиве error_log.

● $type = = 1

Отправляет сообщение по почте адресату, чей адрес указан в $dest. При этом $extra_headers используется в качестве дополнительных почтовых заголовков.

● $type == 3

Сообщение добавляется в конец файла с именем $dest.

 

СТЕК ВЫЗОВОВ ФУНКЦИЙ

 

В РНР версии 4.3.0 и старше существует возможность проследить всю цепочку вызовов функций, начиная от главной программы и заканчивая текущей выполняемой процедурой.

Функция

list debug_backtrace()

возвращает большой список, в котором содержится информация о "родительских" функциях и их аргументах. Результат работы листинга 2.4 говорит сам за себя.

Листинг2.4. Файл trace.php

<?php ## Вывод дерева вызовов функции.

function inner($a) {

 // Внутренняя функция.

 echo "<pre>"; print_r(debug_backtrace()); echo "</pre>";

}

function outer($x) {

 // Родительская функция.

 inner($x*$x);

}

// Главная программа.

outer(3);

?>

После запуска этого скрипта будет напечатан примерно следующий результат (его чуть сжали):

Array (

[0] => Array (

[file] => z:\home\book\original\src\interpreter\trace.php

[line] => 6

[function] => inner

[args] => Array ([0] => 9)

)

[1] => Array (

[file] => z:\home\book\original\src\interpreter\trace.php

[line] => 8

[function] => outer

[args] => Array ([0] => 3)

)

)

Как видите, в массиве оказалась все информация о промежуточных вызовах функций.

Функцию удобно применять, например, в пользовательском обработчике ошибок. Тогда можно сразу же определить, в каком месте было сгенерировано сообщение и какие вызовы к этому привели, В крупных программах уровень вложенности функций может достигать нескольких десятков, поэтому, наверное, вместо print_r() стоит написать свой собственный код для вывода дерева вызовов в более компактной форме.

 

Дата: 2019-05-28, просмотров: 202.