Использование класса Error: создание экземпляров в PHP

Раздел: Программирование на PHP -> Обработка ошибок

Создание объекта Error в PHP: синтаксис и варианты

Основной способ: new Error(string $message, int $code, ?Throwable $previous)

Класс Error появился в PHP 7 для представления фатальных ошибок, которые можно перехватить. Стандартный конструктор принимает три необязательных параметра:

  • $message - текст ошибки (по умолчанию пустая строка);
  • $code - числовой код ошибки (по умолчанию 0);
  • $previous - предыдущее исключение (объект, реализующий Throwable).

$error = new Error('Фатальная ошибка', 500);
echo $error->getMessage(); // Фатальная ошибка
echo $error->getCode();    // 500

Объект обычно выбрасывается через throw, а затем ловится в блоке catch (Error $e). Типичная ошибка - пропуск обязательных аргументов при переопределении конструктора в наследниках (см. проблему ниже).

Проблема: если в пользовательском классе, наследующем Error, переопределён конструктор без вызова родительского, то свойства message и code не инициализируются.

Решение: всегда вызывать parent::__construct($message, $code, $previous) в начале конструктора наследника.

Как создать объект Error без сообщения?

Все параметры конструктора необязательны. Можно написать new Error() - будет создан объект с пустым сообщением и кодом 0. Однако это затрудняет отладку, поэтому рекомендуется указывать хотя бы строку.


$e = new Error();
var_dump($e->getMessage()); // string(0) ""

Проблема: без сообщения узнать причину ошибки невозможно.

Решение: всегда передавать осмысленное сообщение.

Как сохранить цепочку исключений при создании Error?

Третий параметр $previous позволяет привязать предыдущее исключение. Это полезно для логирования и отслеживания последовательности ошибок.


$original = new Exception('База данных недоступна');
$error = new Error('Невозможно выполнить запрос', 0, $original);
echo $error->getPrevious()->getMessage(); // База данных недоступна

Проблема: передача в $previous объекта, который уже ссылается на новый Error, создаёт циклическую ссылку.

Решение: не передавать себя или исключения, которые уже содержат создаваемый объект.

Как создать собственный тип ошибки на основе Error?

Наследование от Error позволяет определить собственные классы для разных категорий ошибок. В наследнике можно добавлять свои методы и свойства.


class ValidationError extends Error {
    private array $errors;
    public function __construct(string $message, array $errors, int $code = 0, ?Throwable $previous = null) {
        parent::__construct($message, $code, $previous);
        $this->errors = $errors;
    }
    public function getErrors(): array {
        return $this->errors;
    }
}

$validationError = new ValidationError('Некорректные данные', ['email' => 'Неверный формат']);
echo $validationError->getErrors()['email']; // Неверный формат

Проблема: если не вызвать parent::__construct, поля message и code останутся пустыми.

Решение: всегда вызывать родительский конструктор с соответствующими аргументами.

Когда использовать Error вместо Exception?

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


// Пример выбора
if (!extension_loaded('pdo')) {
    throw new Error('Расширение PDO не установлено');
}

Расширенные примеры создания и обработки Error

Пример 1. Базовое создание и перехват Error

Пример

try {
    throw new Error('Критическая ошибка', 100);
} catch (Error $e) {
    echo 'Поймана ошибка: ' . $e->getMessage() . ' (код: ' . $e->getCode() . ')';
}
Поймана ошибка: Критическая ошибка (код: 100)

Пример 2. Цепочка исключений с Error

Пример

$prevException = new RuntimeException('Предшествующая ошибка');
$mainError = new Error('Главная ошибка', 500, $prevException);

echo $mainError->getPrevious()->getMessage();
Предшествующая ошибка

Пример 3. Пользовательский класс Error с дополнительной логикой

Пример

class DatabaseError extends Error {
    private $query;
    public function __construct(string $message, string $query, int $code = 0, ?Throwable $previous = null) {
        parent::__construct($message, $code, $previous);
        $this->query = $query;
    }
    public function getQuery(): string {
        return $this->query;
    }
}

try {
    $dbError = new DatabaseError('Запрос не выполнен', 'SELECT * FROM users');
    throw $dbError;
} catch (DatabaseError $e) {
    echo 'Ошибка БД: ' . $e->getMessage() . ' | Запрос: ' . $e->getQuery();
}
Ошибка БД: Запрос не выполнен | Запрос: SELECT * FROM users

Пример 4. Логирование Error в файл

Пример

function logError(Error $error): void {
    $log = date('Y-m-d H:i:s') . ' [' . $error->getCode() . '] ' . $error->getMessage() . PHP_EOL;
    file_put_contents('errors.log', $log, FILE_APPEND);
}

try {
    throw new Error('Не удалось открыть файл', 404);
} catch (Error $e) {
    logError($e);
    echo 'Ошибка залогирована.';
}
// Содержимое errors.log:
// 2025-04-10 12:30:00 [404] Не удалось открыть файл
Ошибка залогирована.

Пример 5. Множественные блоки catch для Error и Exception

Пример

try {
    if (rand(0, 1)) {
        throw new Error('Фатальная ошибка');
    } else {
        throw new InvalidArgumentException('Неверный аргумент');
    }
} catch (Error $e) {
    echo 'Перехвачен Error: ' . $e->getMessage();
} catch (Exception $e) {
    echo 'Перехвачен Exception: ' . $e->getMessage();
}
Перехвачен Error: Фатальная ошибка

Пример 6. Использование Throwable для перехвата любых исключений и ошибок

Пример

try {
    throw new Error('Любая ошибка');
} catch (Throwable $t) {
    echo 'Тип: ' . get_class($t) . ', сообщение: ' . $t->getMessage();
}
Тип: Error, сообщение: Любая ошибка

Создание объекта Error в PHP - comments

En
Php new error (php)