Получение информации об ошибке в php

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

Статья разбита на четыре раздела:

  1. Классификация ошибок.
  2. Пример, демонстрирующий различные виды ошибок и его поведение при различных настройках.
  3. Написание собственного обработчика ошибок.
  4. Полезные ссылки.

Классификация ошибок

Все ошибки, условно, можно разбить на категории по нескольким критериям.
Фатальность:

  • Фатальные
    Неустранимые ошибки. Работа скрипта прекращается.
    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";, то ошибка попадет во вторую группу.

Значение, приведенной выше, таблицы можно описать следующим образом:

  1. Наличие в файле скрипта ошибки, приводящей его в «негодное» состояние (невозможность корректно обработать), на выходе даст пустое значение или же только само сообщение об ошибке, в зависимости от значения директивы display_errors.
  2. Скрипт в файле с фатальной ошибкой, не относящейся к первому пункту, будет выполняться в штатном режиме до самой ошибки.
  3. Наличие в файле фатальной ошибки при display_errors = Off обозначит 500 статус ответа.
  4. Не фатальные ошибки, как и следовало ожидать, в контексте возможности исполнения скрипта в целом, на работоспособность не повлияют.

Собственный обработчик ошибок

Для написания собственного обработчика ошибок необходимо знать, что:

  • для получения информации о последней произошедшей ошибке существует функция 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 и Throwable в PHP

Все типы делятся на две группы: собственно ошибки (класс 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.

Like this post? Please share to your friends:
  • Получение имени канала xmeye ошибка
  • Получена явная ошибка eap 0x50005
  • Получена ошибка сервера сэдо фсс код состояния 500
  • Поиски ошибок в тексте онлайн
  • Поиск устранения ошибок в компьютерной программе