Просмотр ошибок PHP: отображение и логирование
Основные методы отображения ошибок PHP
Как включить вывод ошибок прямо в скрипте?
Самый простой и быстрый способ увидеть ошибки во время разработки - использовать функции ini_set() и error_reporting() в начале скрипта. Этот метод не требует доступа к серверным конфигурациям и работает для любого сайта, если разрешена переопределение директив.
<?php
// Включаем отображение всех ошибок
ini_set('display_errors', '1');
error_reporting(E_ALL);
// Пример кода с ошибкой
echo $undefined_variable;
?>
В результате на экране появится предупреждение о неопределённой переменной. Важно: после отладки следует отключить вывод ошибок на боевом сервере.
Типичные проблемы:
- Ошибки не отображаются, если в php.ini установлено display_errors = Off, но скрипт может переопределить эту директиву, если разрешено (обычно разрешено).
- Некоторые хосты запрещают переопределение через ini_set() - тогда нужно использовать другие методы.
- Уровень E_ALL включает все типы ошибок, включая уведомления и предупреждения. Можно использовать E_ALL & ~E_NOTICE & ~E_STRICT для исключения несущественных сообщений.
Как настроить показ ошибок через файл .htaccess?
Если сервер работает под управлением Apache и доступен файл .htaccess, можно задать директивы PHP прямо в нем. Это полезно, когда нет доступа к php.ini.
php_flag display_errors on
php_value error_reporting 32767 # E_ALL
Цифра 32767 соответствует E_ALL в PHP 5.x; для PHP 7+ она равна 32767, но лучше использовать константу E_ALL (если сервер её поддерживает).
Проблемы:
- Не все хостинги разрешают переопределение этих директив через .htaccess.
- Синтаксис php_value и php_flag может отличаться в зависимости от версии Apache и PHP.
- Если в .htaccess уже есть другие настройки, возможен конфликт.
Как изменить глобальные настройки обработки ошибок через php.ini?
Редактирование основного конфигурационного файла PHP - самый надёжный способ. Подходит для администраторов сервера.
; Включить отображение ошибок
display_errors = On
; Уровень ошибок
error_reporting = E_ALL
; Путь к лог-файлу
error_log = /var/log/php_errors.log
После изменения нужно перезагрузить веб-сервер (Apache, Nginx).
Проблемы:
- Нет доступа к php.ini на общем хостинге.
- Ошибки могут быть скрыты, если display_errors выключен, но error_log включен - тогда они пишутся только в лог.
Как настроить ошибки для конкретной директории через .user.ini?
Начиная с PHP 5.3.0, можно использовать файл .user.ini в корне директории. Это аналог .htaccess, но для CGI/FastCGI.
display_errors = On
error_reporting = E_ALL
Изменения применяются автоматически, перезагрузка сервера не требуется.
Проблемы:
- Работает только при использовании CGI/FastCGI, не для модуля mod_php.
- На некоторых хостингах может быть отключено.
Как временно включить вывод ошибок при запуске скрипта из командной строки?
При выполнении PHP-скрипта в консоли можно передать параметры через -d.
php -d display_errors=1 -d error_reporting=E_ALL script.php
Это удобно для разовой отладки, не меняя конфигурационные файлы.
Проблемы:
- Не применимо для веб-запросов.
- Константу E_ALL нужно указывать в числовом виде, если система не распознает строковое значение.
Как программно перехватить и просмотреть последнюю ошибку?
Функция error_get_last() возвращает массив с информацией о последней произошедшей ошибке. Это полезно для записи в лог или отображения в специальном блоке.
<?php
// Производим действие, которое может вызвать ошибку
$result = file_get_contents('nonexistent.txt');
$error = error_get_last();
if ($error) {
echo 'Тип: ' . $error['type'] . "\n";
echo 'Сообщение: ' . $error['message'] . "\n";
echo 'Файл: ' . $error['file'] . "\n";
echo 'Строка: ' . $error['line'] . "\n";
}
?>
Проблемы:
- error_get_last() возвращает только последнюю ошибку, предыдущие теряются.
- Не работает для фатальных ошибок (E_ERROR, parse error), так как скрипт прерывается до вызова функции.
Как создать собственный обработчик ошибок и исключений?
С помощью set_error_handler() и set_exception_handler() можно перехватывать все ошибки и исключения, направляя их в свой код (например, для красивого вывода или логирования).
<?php
// Функция-обработчик ошибок
function myErrorHandler($errno, $errstr, $errfile, $errline) {
echo "<b>Ошибка:</b> [$errno] $errstr в файле $errfile на строке $errline\n";
return true; // не запускать стандартный обработчик
}
set_error_handler('myErrorHandler');
// Пример
trigger_error('Произошло предупреждение', E_USER_WARNING);
?>
Проблемы:
- Стандартный обработчик не перехватывает фатальные ошибки (E_ERROR, E_PARSE) - для них нужен register_shutdown_function() или использование symfony/error-handler.
- Если функция обработчика сама вызовет ошибку, это может привести к рекурсии.
Как использовать сторонние библиотеки для отладки ошибок?
Библиотеки вроде filp/whoops предоставляют красивое отображение ошибок с трассировкой стека и контекстом. Установка через Composer:
composer require filp/whoops
Затем в скрипте:
<?php
require 'vendor/autoload.php';
$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
$whoops->register();
// Ошибка для демонстрации
echo 1/0;
?>
Результат - страница с подробной информацией об ошибке.
Проблемы:
- Требует установки через Composer и может быть избыточно для простых проектов.
- Не все хосты поддерживают сторонние библиотеки.
Расширенные примеры настройки ошибок PHP
Ниже приведены более детальные примеры с выводом результатов, демонстрирующие различные аспекты управления ошибками.
1. Настройка вывода ошибок и логирования с разными уровнями
Пример показывает, как включить отображение только фатальных ошибок, но при этом логировать все предупреждения.
<?php
// Включаем отображение только фатальных ошибок
ini_set('display_errors', '1');
error_reporting(E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR);
// Логируем всё остальное
ini_set('log_errors', '1');
ini_set('error_log', '/tmp/php_errors.log');
// Генерируем разные ошибки
echo $undefined; // уведомление - будет в лог, но не на экране
trigger_error('Пользовательское предупреждение', E_USER_WARNING); // в лог
function test() { echo 1/0; } // деление на ноль - предупреждение (в лог)
test();
?>
(На экране: Warning: Division by zero in /path/file.php on line 13 ) В файле /tmp/php_errors.log будут все три сообщения.
2. Использование error_get_last для фиксации ошибок доступа к файлам
<?php
$file = @file_get_contents('missing.txt');
$lastError = error_get_last();
if ($lastError !== null) {
echo 'Последняя ошибка: ' . $lastError['message'];
}
// Если несколько ошибок, error_get_last вернет последнюю
// Попробуем два вызова
@file_get_contents('a.txt');
@file_get_contents('b.txt');
$lastError = error_get_last();
echo '; последняя: ' . $lastError['message'];
?>
Последняя ошибка: file_get_contents(missing.txt): Failed to open stream: No such file or directory; последняя: file_get_contents(b.txt): Failed to open stream: No such file or directory
3. Пользовательский обработчик ошибок с классификацией и записью в БД
<?php
function dbErrorHandler($errno, $errstr, $errfile, $errline) {
// Классификация
$type = 'Unknown';
switch ($errno) {
case E_WARNING: $type = 'Warning'; break;
case E_NOTICE: $type = 'Notice'; break;
case E_USER_ERROR: $type = 'User Error'; break;
}
// Запись в БД (пример)
$msg = sprintf('[%s] %s in %s:%d', $type, $errstr, $errfile, $errline);
// file_put_contents('errors.log', $msg.PHP_EOL, FILE_APPEND);
echo "<div class='error'>$msg</div>";
return true;
}
set_error_handler('dbErrorHandler');
trigger_error('Проверка работы обработчика', E_USER_NOTICE);
?>
<div class='error'>[Notice] Проверка работы обработчика in /path/file.php:18</div>
4. Перехват фатальных ошибок через register_shutdown_function
<?php
function fatalHandler() {
$error = error_get_last();
if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
echo 'Фатальная ошибка: ' . $error['message'] . ' в файле ' . $error['file'];
}
}
register_shutdown_function('fatalHandler');
// Вызов несуществующей функции
undefinedFunction();
?>
Фатальная ошибка: Call to undefined function undefinedFunction() in /path/file.php:11
5. Комбинированный подход: вывод ошибок в режиме разработки, скрытие в продакшене
<?php
// Определяем окружение
$env = getenv('APP_ENV') ?: 'production';
if ($env === 'dev' || $env === 'development') {
ini_set('display_errors', '1');
error_reporting(E_ALL);
ini_set('log_errors', '1');
} else {
ini_set('display_errors', '0');
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/app_errors.log');
}
?>
Такой подход позволяет безопасно переключаться между режимами без изменения кода.
6. Использование Xdebug для расширенной отладки
// Установка Xdebug (через pecl или apt)
// В php.ini:
xdebug.mode = develop,debug
xdebug.start_with_request = yes
xdebug.client_host = 127.0.0.1
xdebug.client_port = 9003
Xdebug предоставляет цветной вывод ошибок с трассировкой стека, но требует настройки IDE.