tracerdx at tracerdx dot com ¶
17 years ago
I keep seeing qualification lists for error types/error-nums as arrays; In user notes and in the manual itself. For example, in this manual entry's example, when trying to seperate behavior for the variable trace in the error report:
<?php //...
// set of errors for which a var trace will be saved
$user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);//and later...if (in_array($errno, $user_errors)) {
//...whatever
}//... ?>
I was under the impression that PHP error code values where bitwise flag values. Wouldn't bitwise masking be better? So I propose a slightly better way:
<?php //...$user_errors = E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE;//...blah...if ($errno & $user_errors) {
//...whatever
}//... ?>
Or for those of you who don't like the idea of using an integer as the condition in an if statement:
<?php
if (($errno & $user_errors) > 0) {
//...whatever
}
?>
I think that's much more efficient than using _yet another_ array() constuct and an in_array().
If I am wrong, and the E_* constants aren't supposed to be used in this fashion (ie, the constans aren't guaranteed to be bitwise, which would be odd since that's how they're setup in the php.ini file), then delete me. I just don't see why one should be using arrays when bitwise comparisons will work, considering the bitwise method should be MUCH more efficient.
shawing at gmail dot com ¶
18 years ago
Although the root user writes to the files 'error_log' and 'access_log', the Apache user has to own the file referenced by 'error_log = filename' or no log entries will be written.
; From php.ini
; Log errors to specified file.
error_log = /usr/local/apache/logs/php.errors
[root@www logs]$ ls -l /usr/local/apache/logs/php.errors
-rw-r--r-- 1 nobody root 27K Jan 27 16:58 php.errors
ptah at se dot linux dot org ¶
18 years ago
PHP5 only (only tested with php5.0).
If you, for some reason, prefer exceptions over errors and have your custom error handler (set_error_handler) wrap the error into an exception you have to be careful with your script.
Because if you, instead of just calling the exception handler, throws the exception, and having a custom exception handler (set_exception_handler). And an error is being triggered inside that exception handler, you will get a weird error:
"Fatal error: Exception thrown without a stack frame in Unknown on line 0"
This error is not particulary informative, is it? :)
This example below will cause this error.
<?php
class PHPErrorException extends Exception
{
private $context = null;
public function __construct
($code, $message, $file, $line, $context = null)
{
parent::__construct($message, $code);
$this->file = $file;
$this->line = $line;
$this->context = $context;
}
};
function
error_handler($code, $message, $file, $line) {
throw new PHPErrorException($code, $message, $file, $line);
}
function
exception_handler(Exception $e)
{
$errors = array(
E_USER_ERROR => "User Error",
E_USER_WARNING => "User Warning",
E_USER_NOTICE => "User Notice",
);
echo
$errors[$e->getCode()].': '.$e->getMessage().' in '.$e->getFile().
' on line '.$e->getLine()."n";
echo $e->getTraceAsString();
}set_error_handler('error_handler');
set_exception_handler('exception_handler');// Throw exception with an /unkown/ error code.
throw new Exception('foo', 0);
?>
There are however, easy fix for this as it's only cause is sloppy code.
Like one, directly call exception_handler from error_handler instead of throwing an exception. Not only does it remedy this problem, but it's also faster. Though this will cause a `regular` unhandled exception being printed and if only "designed" error messages are intended, this is not the ultimate solution.
So, what is there to do? Make sure the code in exception_handlers doesn't cause any errors! In this case a simple isset() would have solved it.
regards, C-A B.
Stephen ¶
16 years ago
If you are using PHP as an Apache module, your default behavior may be to write PHP error messages to Apache's error log. This is because the error_log .ini directive may be set equal to "error_log" which is also the name of Apache's error log. I think this is intentional.
However, you can separate Apache errors from PHP errors if you wish by simply setting a different value for error_log. I write mine in the /var/log folder.
mortonda at dgrmm dot net ¶
16 years ago
Note the example code listed here calls date() every time this is called. If you have a complex source base which calls the custom error handler often, it can end up taking quite a bit of time. I ran a profiler on som code and discovered that 50% of the time was spent in the date function in this error handler.
Anonymous ¶
18 years ago
When configuring your error log file in php.ini, you can use an absolute path or a relative path. A relative path will be resolved based on the location of the generating script, and you'll get a log file in each directory you have scripts in. If you want all your error messages to go to the same file, use an absolute path to the file.
In some application development methodologies, there is the concept of an application root directory, indicated by "/" (even on Windows). However, PHP does not seem to have this concept, and using a "/" as the initial character in a log file path produces weird behavior on Windows.
If you are running on Windows and have set, in php.ini:
error_log = "/php_error.log"
You will get some, but not all, error messages. The file will appear at
c:php_error.log
and contain internally generated error messages, making it appear that error logging is working. However, log messages requested by error_log() do NOT appear here, or anywhere else, making it appear that the code containing them did not get processed.
Apparently on Windows the internally generated errors will interpret "/" as "C:" (or possibly a different drive if you have Windows installed elsewhere - I haven't tested this). However, the error_log process apparently can't find "/" - understandably enough - and the message is dropped silently.
theotek AT nowhere DOT org ¶
16 years ago
It is totally possible to use debug_backtrace() inside an error handling function. Here, take a look:
<?php
set_error_handler('errorHandler');
function
errorHandler( $errno, $errstr, $errfile, $errline, $errcontext)
{
echo 'Into '.__FUNCTION__.'() at line '.__LINE__.
"nn---ERRNO---n". print_r( $errno, true).
"nn---ERRSTR---n". print_r( $errstr, true).
"nn---ERRFILE---n". print_r( $errfile, true).
"nn---ERRLINE---n". print_r( $errline, true).
"nn---ERRCONTEXT---n".print_r( $errcontext, true).
"nnBacktrace of errorHandler()n".
print_r( debug_backtrace(), true);
}
function
a( )
{
//echo "a()'s backtracen".print_r( debug_backtrace(), true);
asdfasdf; // oops
}
function
b()
{
//echo "b()'s backtracen".print_r( debug_backtrace(), true);
a();
}b();
?>
Outputs:
<raw>
Into errorhandler() at line 9
---ERRNO---
8
---ERRSTR---
Use of undefined constant asdfasdf - assumed 'asdfasdf'
---ERRFILE---
/home/theotek/test-1.php
---ERRLINE---
23
---ERRCONTEXT---
Array
(
)
Backtrace of errorHandler()
Array
(
[0] => Array
(
[function] => errorhandler
[args] => Array
(
[0] => 8
[1] => Use of undefined constant asdfasdf - assumed 'asdfasdf'
[2] => /home/theotek/test-1.php
[3] => 23
[4] => Array
(
)
)
)
[1] => Array
(
[file] => /home/theotek/test-1.php
[line] => 23
[function] => a
)
[2] => Array
(
[file] => /home/theotek/test-1.php
[line] => 30
[function] => a
[args] => Array
(
)
)
[3] => Array
(
[file] => /home/theotek/test-1.php
[line] => 33
[function] => b
[args] => Array
(
)
)
)
</raw>
So, the first member of the backtrace's array is not really surprising, except from the missing "file" and "line" members.
The second member of the backtrace seem the be a hook inside the zend engine that is used to trigger the error.
Other members are the normal backtrace.
jbq at caraldi dot com ¶
15 years ago
Precision about error_log when configured with syslog: the syslog() call is done with severity NOTICE.
petrov dot michael () gmail com ¶
16 years ago
I have found that on servers that enforce display_errors to be off it is very inconvenient to debug syntax errors since they cause fatal startup errors. I have used the following method to bypass this limitation:
The syntax error is inside the file "syntax.php", therefore I create a file "syntax.debug.php" with the following code:
<?php
error_reporting(E_ALL);
ini_set('display_errors','On');
include(
'syntax.php');
?>
The 5 line file is guaranteed to be free of errors, allowing PHP to execute the directives within it before including the file which previously caused fatal startup errors. Now those fatal startup errors become run time fatal errors.
Обработка и логирование ошибок
- Введение
- Установка и настройка
- Требования
- Установка
- Настройка во время выполнения
- Типы ресурсов
- Предопределённые константы
- Примеры
- Функции обработки ошибок
- debug_backtrace — Выводит стек вызовов функций в массив
- debug_print_backtrace — Выводит стек вызовов функций
- error_clear_last — Очистить самую последнюю ошибку
- error_get_last — Получение информации о последней произошедшей ошибке
- error_log — Отправляет сообщение об ошибке заданному обработчику ошибок
- error_reporting — Задаёт, какие ошибки PHP попадут в отчёт
- restore_error_handler — Восстанавливает предыдущий обработчик ошибок
- restore_exception_handler — Восстанавливает предыдущий обработчик исключений
- set_error_handler — Задаёт пользовательский обработчик ошибок
- set_exception_handler — Задаёт пользовательский обработчик исключений
- trigger_error — Вызывает пользовательскую ошибку/предупреждение/уведомление
- user_error — Псевдоним trigger_error
There are no user contributed notes for this page.
Время на прочтение
6 мин
Количество просмотров 66K
В статье представлена очередная попытка разобраться с ошибками, которые могут встретиться на вашем пути php-разработчика, их возможная классификация, примеры их возникновения, влияние ошибок на ответ клиенту, а также инструкции по написанию своего обработчика ошибок.
Статья разбита на четыре раздела:
- Классификация ошибок.
- Пример, демонстрирующий различные виды ошибок и его поведение при различных настройках.
- Написание собственного обработчика ошибок.
- Полезные ссылки.
Классификация ошибок
Все ошибки, условно, можно разбить на категории по нескольким критериям.
Фатальность:
- Фатальные
Неустранимые ошибки. Работа скрипта прекращается.
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR. - Не фатальные
Устранимые ошибки. Работа скрипта не прекращается.
E_WARNING, E_NOTICE, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING, E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED. - Смешанные
Фатальные, но только, если не обработаны функцией, определенной пользователем в set_error_handler().
E_USER_ERROR, E_RECOVERABLE_ERROR.
Возможность перехвата ошибки функцией, определенной в set_error_handler():
- Перехватываемые (не фатальные и смешанные)
E_USER_ERROR, E_RECOVERABLE_ERROR, E_WARNING, E_NOTICE, E_USER_WARNING, E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED. - Не перехватываемые (фатальные)
E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING.
Инициатор:
- Инициированы пользователем
E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE. - Инициированы PHP
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_WARNING, E_NOTICE, E_CORE_WARNING, E_COMPILE_WARNING, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED, E_USER_ERROR, E_RECOVERABLE_ERROR.
Для нас, в рамках данной статьи, наиболее интересны классификации по первым двум критериям, о чем будет рассказано далее.
Примеры возникновения ошибок
Листинг index.php
<?php
// определеяем уровень протоколирования ошибок
error_reporting(E_ALL | E_STRICT);
// определяем режим вывода ошибок
ini_set('display_errors', 'On');
// подключаем файл с ошибками
require 'errors.php';
Листинг errors.php
<?php
echo "Файл с ошибками. Начало<br>";
/*
* перехватываемые ошибки (ловятся функцией set_error_handler())
*/
// NONFATAL - E_NOTICE
// echo $undefined_var;
// NONFATAL - E_WARNING
// array_key_exists('key', NULL);
// NONFATAL - E_DEPRECATED
split('[/.-]', "12/21/2012"); // split() deprecated начиная с php 5.3.0
// NONFATAL - E_STRICT
// class c {function f(){}} c::f();
// NONFATAL - E_USER_DEPRECATED
// trigger_error("E_USER_DEPRECATED", E_USER_DEPRECATED);
// NONFATAL - E_USER_WARNING
// trigger_error("E_USER_WARNING", E_USER_WARNING);
// NONFATAL - E_USER_NOTICE
// trigger_error("E_USER_NOTICE", E_USER_NOTICE);
// FATAL, если не обработана функцией set_error_handler - E_RECOVERABLE_ERROR
// class b {function f(int $a){}} $b = new b; $b->f(NULL);
// FATAL, если не обработана функцией set_error_handler - E_USER_ERROR
// trigger_error("E_USER_ERROR", E_USER_ERROR);
/*
* неперехватываемые (не ловятся функцией set_error_handler())
*/
// FATAL - E_ERROR
// undefined_function();
// FATAL - E_PARSE
// parse_error
// FATAL - E_COMPILE_ERROR
// $var[];
echo "Файл с ошибками. Конец<br>";
Примечание: для полной работоспособности скрипта необходим PHP версии не ниже 5.3.0.
В файле errors.php представлены выражения, инициирующие практически все возможные ошибки. Исключение составили: E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_WARNING, генерируемые ядром Zend. В теории, встретить их в реальной работе вы не должны.
В следующей таблице приведены варианты поведения этого скрипта в различных условиях (в зависимости от значений директив display_errors и error_reporting):
Группа ошибок | Значения директив* | Статус ответа сервера | Ответ клиенту** |
---|---|---|---|
E_PARSE, E_COMPILE_ERROR*** | display_errors = off error_reporting = ANY |
500 | Пустое значение |
display_errors = on error_reporting = ANY |
200 | Сообщение об ошибке | |
E_USER_ERROR, E_ERROR, E_RECOVERABLE_ERROR | display_errors = off error_reporting = ANY |
500 | Вывод скрипта до ошибки |
display_errors = on error_reporting = ANY |
200 | Сообщение об ошибке и вывод скрипта до ошибки | |
Не фатальные ошибки | display_errors = off error_reporting = ANY и display_errors = on error_reporting = 0 |
200 | Весь вывод скрипта |
display_errors = on error_reporting = E_ALL | E_STRICT |
200 | Сообщение об ошибке и весь вывод скрипта |
* Значение ANY означает E_ALL | E_STRICT или 0.
** Ответ клиенту может отличаться от ответов на реальных скриптах. Например, вывод какой-либо информации до включения файла errors.php, будет фигурировать во всех рассмотренных случаях.
*** Если в файле errors.php заменить пример для ошибки E_COMPILE_ERROR на require "missing_file.php";
, то ошибка попадет во вторую группу.
Значение, приведенной выше, таблицы можно описать следующим образом:
- Наличие в файле скрипта ошибки, приводящей его в «негодное» состояние (невозможность корректно обработать), на выходе даст пустое значение или же только само сообщение об ошибке, в зависимости от значения директивы display_errors.
- Скрипт в файле с фатальной ошибкой, не относящейся к первому пункту, будет выполняться в штатном режиме до самой ошибки.
- Наличие в файле фатальной ошибки при display_errors = Off обозначит 500 статус ответа.
- Не фатальные ошибки, как и следовало ожидать, в контексте возможности исполнения скрипта в целом, на работоспособность не повлияют.
Собственный обработчик ошибок
Для написания собственного обработчика ошибок необходимо знать, что:
- для получения информации о последней произошедшей ошибке существует функция error_get_last();
- для определения собственного обработчика ошибок существует функция set_error_handler(), но фатальные ошибки нельзя «перехватить» этой функцией;
- используя register_shutdown_function(), можно зарегистрировать свою функцию, выполняемую по завершении работы скрипта, и в ней, используя знания из первого пункта, если фатальная ошибка имела место быть, предпринять необходимые действия;
- сообщение о фатальной ошибке в любом случае попадет в буфер вывода;
- воспользовавшись функциями контроля вывода можно предотвратить отображение нежелательной информации;
- при использовании оператора управления ошибками (знак @) функция, определенная в set_error_handler() все равно будет вызвана, но функция error_reporting() в этом случае вернет 0, чем и можно пользоваться для прекращения работы или определения другого поведения своего обработчика ошибок.
Третий пункт поясню: зарегистрированная нами функция при помощи register_shutdown_function() выполнится в любом случае — корректно ли завершился скрипт, либо же был прерван в связи с критичной (фатальной) ошибкой. Второй вариант мы можем однозначно определить, воспользовавшись информацией предоставленной функцией error_get_last(), и, если ошибка все же была, выполнить наш собственный обработчик ошибок.
Продемонстрируем вышесказанное на модифицированном скрипте index.php:
<?php
/**
* Обработчик ошибок
* @param int $errno уровень ошибки
* @param string $errstr сообщение об ошибке
* @param string $errfile имя файла, в котором произошла ошибка
* @param int $errline номер строки, в которой произошла ошибка
* @return boolean
*/
function error_handler($errno, $errstr, $errfile, $errline)
{
// если ошибка попадает в отчет (при использовании оператора "@" error_reporting() вернет 0)
if (error_reporting() & $errno)
{
$errors = array(
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE',
E_STRICT => 'E_STRICT',
E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
E_DEPRECATED => 'E_DEPRECATED',
E_USER_DEPRECATED => 'E_USER_DEPRECATED',
);
// выводим свое сообщение об ошибке
echo "<b>{$errors[$errno]}</b>[$errno] $errstr ($errfile на $errline строке)<br />n";
}
// не запускаем внутренний обработчик ошибок PHP
return TRUE;
}
/**
* Функция перехвата фатальных ошибок
*/
function fatal_error_handler()
{
// если была ошибка и она фатальна
if ($error = error_get_last() AND $error['type'] & ( E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR))
{
// очищаем буффер (не выводим стандартное сообщение об ошибке)
ob_end_clean();
// запускаем обработчик ошибок
error_handler($error['type'], $error['message'], $error['file'], $error['line']);
}
else
{
// отправка (вывод) буфера и его отключение
ob_end_flush();
}
}
// определеяем уровень протоколирования ошибок
error_reporting(E_ALL | E_STRICT);
// определяем режим вывода ошибок
ini_set('display_errors', 'On');
// включаем буфферизацию вывода (вывод скрипта сохраняется во внутреннем буфере)
ob_start();
// устанавливаем пользовательский обработчик ошибок
set_error_handler("error_handler");
// регистрируем функцию, которая выполняется после завершения работы скрипта (например, после фатальной ошибки)
register_shutdown_function('fatal_error_handler');
require 'errors.php';
Не забываем, что ошибки смешанного типа, после объявления собственного обработчика ошибок, стали не фатальными. Плюс к этому, весь вывод скрипта до фатальной ошибки вместе с стандартным сообщением об ошибке будет сброшен.
Вообще, рассмотренный пример обработчика ошибок, обработкой, как таковой, не занимается, а только демонстрирует саму возможность. Дальнейшее его поведение зависит от ваших желаний и/или требований. Например, все случаи обращения к обработчику можно записывать в лог, а в случае фатальных ошибок, дополнительно, уведомлять об этом администратора ресурса.
Полезные ссылки
- Первоисточник: php.net/manual/ru/book.errorfunc.php
- Описание ошибок: php.net/manual/ru/errorfunc.constants.php
- Функции контроля вывода: php.net/manual/ru/ref.outcontrol.php
- Побитовые операторы: php.net/manual/ru/language.operators.bitwise.php и habrahabr.ru/post/134557
- Тематически близкая статья: habrahabr.ru/post/134499
За последние 24 часа нас посетили 11513 программистов и 601 робот. Сейчас ищут 680 программистов …
Обработка и протоколирование ошибок
- Введение
- Установка и настройка
- Требования
- Установка
- Настройка во время выполнения
- Типы ресурсов
- Предопределенные константы
- Примеры
- Функции обработки ошибок
- debug_backtrace — Выводит стек вызовов функций в массив
- debug_print_backtrace — Выводит стек вызовов функций
- error_clear_last — Clear the most recent error
- error_get_last — Получение информации о последней произошедшей ошибке
- error_log — Отправляет сообщение об ошибке заданному обработчику ошибок
- error_reporting — Задает, какие ошибки PHP попадут в отчет
- restore_error_handler — Восстанавливает предыдущий обработчик ошибок
- restore_exception_handler — Восстанавливает предыдущий обработчик исключений
- set_error_handler — Задает определенный пользователем обработчик ошибок
- set_exception_handler — Задает пользовательский обработчик исключений
- trigger_error — Вызывает пользовательскую ошибку/предупреждение/уведомление
- user_error — Синоним для trigger_error
Вернуться к: Изменение поведения PHP
Обработка исключений
Конструкция try catch finally
Последнее обновление: 24.03.2021
В процессе работы программы могут возникать различные ошибки, которые могут прервать работу программы. Например, рассмотрим следующую ситуацию:
$a = 5; $b = 0; $result = $a / $b; echo $result; echo "Конец работы программы";
Программа выводит результат деления. Поскольку делитель равен 0, а на ноль делить нельзя, то при выполнении деления программа завершится, и в браузере мы увидим
что-то типа следующего:
Fatal error: Uncaught DivisionByZeroError: Division by zero in D:localhosthello.php:11 Stack trace: #0 {main} thrown in D:localhosthello.php on line 11
Браузер отобразит нам произошедшую ошибку, причем дальше после строки с делением программа даже не будет выполняться.
Кто-то может сказать, что ситуация искуственная, так как мы сами определили делитель равный нулю. Но данные могут передаваться извне. Кроме того, кроме деления на ноль есть различные
ситуации, при которых могут происходить ошибки. Но PHP предоставляет ряд возможностей для обработки подобных ситуаций.
Для обработки исключений в PHP применяется конструкция try-catch:
try { // код, который может вызвать исключение } catch(Тип_исключения $ex) { // обработка исключения }
Эта конструкция в общем варианте состоит из двух блоков — try
и catch
. В блок try
помещается код, который потенциально может вызвать исключение.
А в блоке catch
помещается обработка возникшего исключения. Причем каждого типа исключения мы можем определить свою логику обработки. Конкретный тип исключения,
который мы хотим обработать, указывается в круглых скобках после оператора catch
:
catch(Тип_исключения $ex)
После названия типа указывается переменная этого типа (в данном случае $ex
), которая будет хранить информацию об исключении и которую мы можем использовать
при обработке исключения.
Если в блоке try
при выполнении кода возникает ошибка, то блок try
прекращает выполнение и передает управление блоку catch
, который обрабатывает ошибку.
А после завершения выполнения кода в блоке catch
программа продолжает выполнять инструкции, которые размещены после блока catch
.
Если в блоке try
при выполнении кода не возникает ошибок, то блок catch
не выполняется, а после завершения блока try
программа продолжает выполнять инструкции, которые размещены после блока catch
.
Например, обработаем ошибку с делением на ноль:
try { // код, который может вызвать исключение $a = 5; $b = 0; $result = $a / $b; echo $result; } catch(DivisionByZeroError $ex) { // обработка исключения echo "Произошло исключение:<br>"; echo $ex . "<br>"; } echo "Конец работы программы";
В данном случае код деления на ноль, поскольку он может потенциально вызвать ошибку, помещен в блок try
.
В блоке catch
обрабатывается ошибка типа DivisionByZeroError, которая генерируется при делении на ноль. Вся обработка сводится
к выводу информации на экран.
В итоге при выполнении программа выведет следующее:
Произошло исключение: DivisionByZeroError: Division by zero in D:localhosthello.php:14 Stack trace: #0 {main} Конец работы программы
Как видно из вывода программы, она не завершается аварийно при делении на ноль, а продолжает работу.
Типы ошибок и исключений
В PHP для разных ситуаций есть множество типов, которые описывают ошибки. Все эти встроенные типы применяют интерфейс Throwable:
Все типы делятся на две группы: собственно ошибки (класс Error) и собственно исключения (класс Exception).
А от классов Error
и Exception
наследуются классы ошибок и исключений, которые описывают конкретные ситуации. Например, от класса
Error
наследуется класс ArithmeticError, который описывает ошибки, возникающие при выполнении арифметических операций.
А от класса ArithmeticError
наследуется класс DivisionByZeroError, который представляют ошибку при делении на ноль.
Блок catch
Конструкция try..catch
позволяет определить несколько блоков catch
— для обработки различных типов ошибок и исключений:
try { $result = 5 / 0; echo $result; } catch(ParseError $p) { echo "Произошла ошибка парсинга"; } catch(DivisionByZeroError $d) { echo "На ноль делить нельзя"; }
При возникновении ошибки будет для ее обработки будет выбираться тот блок catch
, который соответствует вошникшей ошибки. Так, в данном случае
при делении на ноль будет выполняться второй блок catch
.
Если бы в блоке try
возникла бы ошибка, которая бы не соответствовала типам из блоков catch
(в данном случае — типам DivisionByZeroError и ParseError),
то такая ошибка не была бы обработана, и соответственно программа бы аварийно завершила свое выполнение.
Блоки catch с более конкретными типами ошибок и исключений должны идти в начале, а более с более общими типа — в конце:
try { $result = 5 / 0; echo $result; } catch(DivisionByZeroError $ex) { echo "На ноль делить нельзя"; } catch(ArithmeticError $ex) { echo "Ошибка при выполнении арифметической операции"; } catch(Error $ex) { echo "Произошла ошибка"; } catch(Throwable $ex) { echo "Ошибка при выполнении программы"; }
Класс DivisionByZeroError унаследован от ArithmeticError, который, в свою очередь, унаследован от Error, реализующего интерфейс Throwable. Поэтому
класс DivisionByZeroError представляет более конкретный тип и представляемые им ошибки должны обрабатываться в первую очередь. А тип Throwable представляет
наиболее общий тип, так как ему соответствуют все возможные ошибки и исключения, поэтому блоки catch с таким типом должны идти в конце.
В данном случае опять же в блоке try происходит ошибка деления на ноль. Но этой ошибке соответствуют все четыре блока catch
. Для обработки PHP будет
выбирать первый попавшийся, который соответствует типу ошибки. В данном случае это блок для обработки ошибки типа DivisionByZeroError.
Если нам надо обрабатывать в принципе все ошибки и исключения, то мы можем определить только обработку общего для всех них типа Throwable:
try { $result = 5 / 0; echo $result; } catch(Throwable $ex) { echo "Ошибка при выполнении программы"; }
Начиная с версии PHP 8.0 в блоке catch можно просто указать тип обрабатываемого исключения, не определяя переменную:
catch(DivisionByZeroError) { echo "Произошло исключение: деление на ноль"; }
Получение информации об ошибках и исключениях
Интерфейс Throwable
предоставляет ряд методов, которые позволяют получить некоторую информацию о возникшем исключении:
-
getMessage(): возвращает сообщение об ошибке
-
getCode(): возвращает код исключения
-
getFile(): возвращает название файла, в котором возникла ошибка
-
getLine(): возвращает номер строки, в которой возникла ошибка
-
getTrace(): возвращает трассировку стека
-
getTraceAsString(): возвращает трассировку стека в виде строки
Применим некоторые из этих методов:
try { $result = 5 / 0; echo $result; } catch(DivisionByZeroError $ex) { echo "Сообщение об ошибке: " . $ex->getMessage() . "<br>"; echo "Файл: " . $ex->getFile() . "<br>"; echo "Номер строки: " . $ex->getLine() . "<br>"; }
Результат работы:
Сообщение об ошибке: Division by zero Файл: D:localhosthello.php Номер строки: 11
Блок finally
Конструкция try..catch
также может определять блок finally. Этот блок выполняется в конце — после блока try и catch
вне зависимости, возникла или нет ошибка. Нередко блок finally
используется для закрытия ресурсов, которые применяются в блоке try.
try { $result = 5 / 0; echo $result . "<br>"; } catch(Throwable $ex) { echo "Ошибка при выполнении программы<br>"; } finally { echo "Блок finally<br>"; } echo "Конец работы программы";
Вывод программы:
Ошибка при выполнении программы Блок finally Конец работы программы
Конструкция try..catch..finally
может содержать либо все три блока, либо только два блока try
и либо блок catch
,
либо блок finally
.