Ошибки PHP
Узнайте об уровнях ошибок PHP, константах E_*, разнице между ошибками и исключениями, настройке отчётов и лучших практиках обработки ошибок.
Встреча с ошибками — это нормальная часть написания кода на PHP. Чем быстрее вы научитесь читать ошибку, понимать её уровень, причину и способ реакции, тем быстрее вы будете выпускать рабочий код. На этой странице объясняются уровни ошибок PHP (константы E_*), разница между ошибками и исключениями в современном PHP, а также практический подход к отчётности, логированию и обработке ошибок.
Уровни ошибок PHP
Когда PHP обнаруживает проблему, он сигнализирует о ней на определённом уровне, идентифицируемом константой E_*. Уровень говорит о серьёзности проблемы и о том, продолжит ли скрипт выполнение. Эти константы комбинируются с error_reporting() и директивой error_reporting в php.ini, чтобы определить, какие уровни отображаются или логируются.
| Константа | Останавливает скрипт? | Значение |
|---|---|---|
E_ERROR | Да | Фатальная ошибка во время выполнения, например вызов неопределённой функции. |
E_WARNING | Нет | Предупреждение во время выполнения, например include отсутствующего файла. |
E_PARSE | Да | Синтаксическая ошибка во время компиляции; файл так и не запускается. |
E_NOTICE | Нет | Незначительная проблема, например чтение неопределённой переменной. |
E_DEPRECATED | Нет | Функция ещё работает, но будет удалена в будущей версии. |
E_USER_ERROR / E_USER_WARNING / E_USER_NOTICE | Зависит | Уровни, которые вы сами генерируете с помощью trigger_error(). |
E_STRICT | Нет | Рекомендации для совместимого с будущими версиями кода (включены в E_ALL начиная с PHP 7). |
E_ALL | — | Битовая маска, включающая все уровни — используйте это при разработке. |
Это битовые константы, поэтому их можно комбинировать оператором побитового ИЛИ (|) и исключать уровни с помощью & и ~:
<?php
// Report everything except notices and deprecations
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);Важно: Начиная с PHP 8.0, многие бывшие предупреждения и уведомления были повышены до бросаемых исключений
Error(например, чтение неопределённого ключа массива теперь вызывает предупреждение, а вызов неопределённого метода бросаетError). Важно понимать, является ли проблема поднятой ошибкой или брошенным исключением — это определяет способ её перехвата (см. ниже).
Ошибки и исключения
В PHP есть два связанных, но раздельных механизма:
- Традиционные ошибки поднимаются движком и маршрутизируются через
error_reporting,display_errorsи необязательный обработчик, установленный с помощьюset_error_handler(). Это не объекты, которые можно перехватить черезcatch(если только ваш обработчик не преобразует их). - Исключения — это объекты, которые вы
throw-аете и перехватываете с помощью блоковtry/catch. Начиная с PHP 7, фатальные ошибки движка тоже бросаются как объектыError(например,TypeErrorилиDivisionByZeroError), и оба —ExceptionиError— реализуют интерфейсThrowable, поэтомуcatch (\Throwable $e)перехватывает всё, что можно поймать.
<?php
try {
// intdiv() throws a DivisionByZeroError on division by zero
echo intdiv(10, 0);
} catch (\Throwable $e) {
echo get_class($e) . ": " . $e->getMessage();
}
// Output: DivisionByZeroError: Division by zeroРаспространённые причины ошибок PHP
Большинство ошибок восходит к небольшому набору причин:
- Синтаксические ошибки — пропущенная точка с запятой или несовпадающая скобка (
E_PARSE). - Неопределённые символы — использование переменной, константы, функции или ключа массива, которые не существуют.
- Несовпадение типов — передача значения неправильного типа в типизированный параметр (бросает
TypeError). - Устаревшие возможности — функции или синтаксис, намеченные к удалению (
E_DEPRECATED). - Ограничения ресурсов — исчерпание
memory_limitили превышениеmax_execution_time. - Внешние сбои — отсутствующий файл или отказ соединения с базой данных/API либо истечение его времени ожидания.
- Неперехваченные исключения —
throwбез соответствующегоcatch, что превращается в фатальную ошибку.
<?php
// Reading an undefined variable raises an E_WARNING and yields null
echo $undefined_variable ?? "fallback";
// Output: fallbackОператор объединения с null (??) в примере выше — это идиоматический способ прочитать значение, которое может быть неопределённым, без вызова предупреждения.
Настройка отчётности об ошибках
Управляйте тем, какие уровни отображаются и куда они направляются. При разработке показывайте всё; в продакшене скрывайте ошибки от пользователей, но логируйте их.
<?php
// Development: show all errors on screen
error_reporting(E_ALL);
ini_set('display_errors', '1');
// Production: hide from users, write to the error log instead
// error_reporting(E_ALL);
// ini_set('display_errors', '0');
// ini_set('log_errors', '1');Эквивалентные настройки в php.ini: error_reporting, display_errors, log_errors и error_log. Для программного управления смотрите error_reporting(), а для получения последней ошибки используйте error_get_last().
Обработка ошибок в коде
Существуют три взаимодополняющих инструмента:
1. Перехватывайте исключения с помощью try/catch, чтобы восстановимый сбой не завершал скрипт:
<?php
function safeDivide(int $a, int $b): float
{
if ($b === 0) {
throw new InvalidArgumentException("Cannot divide by zero");
}
return $a / $b;
}
try {
echo safeDivide(10, 0);
} catch (InvalidArgumentException $e) {
echo "Handled: " . $e->getMessage();
}
// Output: Handled: Cannot divide by zero2. Установите пользовательский обработчик ошибок с помощью set_error_handler(), чтобы преобразовывать традиционные ошибки в исключения или логировать их в собственном формате:
<?php
set_error_handler(function (int $level, string $message, string $file, int $line) {
// Turn a traditional warning/notice into an ErrorException so it can be caught
throw new ErrorException($message, 0, $level, $file, $line);
});
try {
// Reading a missing file raises an E_WARNING, now converted to an exception
$contents = file_get_contents('/no/such/file.txt');
} catch (\Throwable $e) {
echo "Caught: " . $e->getMessage();
}
// Output: Caught: file_get_contents(/no/such/file.txt): Failed to open stream: No such file or directory3. Генерируйте собственные ошибки с помощью trigger_error(), чтобы сигнализировать о проблемах уровня приложения через тот же конвейер, что и ошибки движка.
Лучшие практики
- Устанавливайте
display_errorsв0в продакшене — утечка трассировок стека является угрозой безопасности. Вместо этого используйтеlog_errorsс настроеннымerror_log. - При разработке используйте
error_reporting(E_ALL), чтобы уведомления и предупреждения об устаревших функциях проявлялись как можно раньше. - Предпочитайте
catch (\Throwable $e)на верхнем уровне для перехвата иException, иError. - Никогда не заглушайте проблемы оператором
@; устраняйте причину или обрабатывайте её явно. - Централизуйте логирование с помощью
error_log(), чтобы все сбои попадали в одно место.
Заключение
Чтение ошибки PHP начинается с определения её уровня и того, является ли она поднятой ошибкой или брошенным исключением. С error_reporting(), настроенным для каждой среды, пользовательским обработчиком, направляющим ошибки в систему исключений, и try/catch вокруг потенциально проблемного кода, вы сможете быстро диагностировать проблемы и обеспечить устойчивость продакшена. Продолжайте с PHP Exceptions и error_reporting() для более глубокого изучения.