на тему рефераты Информационно-образоательный портал
Рефераты, курсовые, дипломы, научные работы,
на тему рефераты
на тему рефераты
МЕНЮ|
на тему рефераты
поиск
Обработка ошибок в коде программ РНР
случае если пользовательский обработчик возвращает значение 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");

?>

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

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

Функция

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.

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

В РНР версии 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() стоит написать свой собственный код для вывода дерева вызовов в более компактной форме.

2.6 ПРИНУДИТЕЛЬНОЕ ЗАВЕРШЕНИЕ ПРОГРАММЫ

Функция

void exit ()

немедленно завершает работу сценария. Из нее никогда не происходит возврата. Перед окончанием программы вызываются функции-финализаторы.

void die(string $message)

Функция делает почти то же самое, что и exit (), только перед завершением работы выводит строку, заданную в параметре $message). Чаще всего ее применяют, если нужно напечатать сообщение об ошибке и аварийно завершить программу.

Полезным примером использования die () может служить такой код:

$filename = '/path/to/data-file';

$file = @fopen($filename, 'r')

or die("не могу открыть файл $ filename!");

Здесь мы ориентируемся на специфику оператора or -- "выполнять" второй операнд только тогда, когда первый "ложен". Заметьте, что оператор || здесь применять нельзя -- он имеет более высокий приоритет, чем =.

С использованием || последний пример нужно было бы переписать следующим образом:

$filename = '/path/to/data-file';

($file = fopen($filename, 'r'))

|| die("не могу открыть файл $filename!");

Согласитесь, громоздкость последнего примера практически полностью исключает возможность применения || в подобных конструкциях.

2.7 ФИНАЛИЗАТОРЫ

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

Во-первых, написать саму функцию и дать ей любое имя. Желательно также, чтобы она была небольшой и в ней не было ошибок, потому что сама функция, вполне возможно, будет вызываться перед завершением сценария из-за ошибки.

Во-вторых, зарегистрировать ее как финализатор, передав ее имя стандартной функции register_shutdown_function().

int register_shutdown_function(string $func)

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

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

Правда, есть одно "но". Финальная функция вызывается уже после закрытия соединения с браузером клиента. Поэтому все данные, выведенные в ней через echo, теряются (во всяком случае, так происходит в Unix-версии РНР, а под Windows CGI-версия РНР и echo работают прекрасно). Так что лучше не выводить никаких данных в такой функции, а ограничиться работой с файлами и другими вызовами, которые ничего не направляют в браузер.

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

3. ПЕРЕХВАТ ОШИБОК. МЕТОД ИСКЛЮЧЕНИЙ

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

Концепция исключений базируется на общей идее объектно-ориентированного программирования: данные должны обрабатываться в том участке программы, который имеет максимум сведений
о том, как это делать. Если в некотором месте еще не до конца известно, какое именно преобразование должно быть выполнено, лучше отложить работу "на потом". С использованием исключений код обработки ошибки явно отделяется от кода, в котором ошибка может возникнуть.

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

3.1 БАЗОВЫЙ СИНТАКСИС

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

Любое исключение в программе представляет собой объект некоторого класса, создаваемый, как обычно, оператором new. Этот объект может содержать различную информацию, например, текст диагностического сообщения, а также номер строки и имя файла, в которых произошла генерация исключения. Допустимо добавлять и любые другие параметры.

Прежде чем идти дальше, давайте рассмотрим простейший пример вызова обработчика (листинг 3.1). Заодно получим представление о синтаксисе исключений.

Листинг.3.1. Файл simple.php

<?php ## Простой пример использования исключений.

echo "Начало программы.<br>";

try {

// Код, в котором перехватываются исключения.

echo "Все, что имеет начало...<br>";

// Генерируем ("выбрасываем") исключение.

throw new Exception("Hello!");

echo "...имеет и конец.<br>";

} catch (Exception $e) {

// Код обработчика.

echo " Исключение: {$e->getMessage()}<br>";

}

echo "Конец программы.<br>";

?>

В листинге 3.1 приведен пример базового синтаксиса конструкции try...catch, применяемой для работы с исключениями.

Рассмотрим эту инструкцию подробнее:

? Код обработчика исключения помещается в блок инструкции catch (в переводе с английского -- "ловить").

? Блок try (в переводе с английского -- "попытаться") используется для того, чтобы указать в программе область перехвата. Любые исключения, сгенерированные внутри нее (и только они), будут переданы соответствующему обработчику.

? Инструкция throw используется для генерации исключения. Генерацию также называют возбуждением или даже выбрасыванием (или "вбрасыванием") исключения (от англ. throw -- бросать). Как было замечено ранее, любое исключение представляет собой обычный объект РНР, который мы и создаем в операторе new.

? Обратите внимание на аргумент блока catch. В нем указано, в какую переменную должен быть записан "пойманный" объект-исключение перед запуском кода обработчика. Также обязательно задается тип исключения -- имя класса. Обработчик будет вызван только для тех объектов-исключений, которые совместимы с указанным типом (например, для объектов данного типа).

Работа инструкции try...catch заключается в том, что одна часть программы "бросает" (throw) исключение, а другая -- его "ловит" (catch).

3.2 ИНСТРУКЦИЯ throw

Инструкция
throw не просто генерирует объект-исключение и передает его обработчику блока catch. Она также немедленно завершает работу текущего try-блока. Именно поэтому результат работы сценария из листинга 3.1 выглядит так:

Начало программы.

Все, что имеет начало...

Исключение: Hello!

Конец программы.

Как видите, за счет особенности инструкции throw наша программа подвергает серьезному скепсису тезис "Все, что имеет начало, имеет и конец" -- она просто не выводит окончание фразы.

В этом отношении инструкция throw очень похожа на инструкции return, break и continue: они тоже приводят к немедленному завершению работы текущей функции или итерации цикла.

3.3 РАСКРУТКА СТЕКА

Самой важной и полезной особенностью инструкции
throw является то, что ее можно использовать не только непосредственно в try-блоке, но и внутри любой функции, которая оттуда вызывается. При этом производится выход не только из функции, содержащей throw, но также и из всех промежуточных процедур. Пример -- в листинге 3.2.

Страницы: 1, 2, 3, 4, 5, 6



© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент.