Обработка TypeError в PHP: практические решения

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

Понимание и устранение необработанной ошибки типа (TypeError) в PHP

Ошибка типа (TypeError) возникает, когда значение не соответствует ожидаемому типу, объявленному в сигнатуре функции, метода или свойства. Это особенно актуально при включённом строгом режиме типизации (declare(strict_types=1)). Необработанное исключение (uncaught TypeError) останавливает выполнение скрипта. Ниже рассматриваются способы перехвата и корректной обработки таких ошибок.

Как перехватить TypeError с помощью try-catch и корректно завершить выполнение?

Наиболее эффективный метод - заключить потенциально проблемный код в блок try и ловить исключение TypeError (или его родительский класс Error) в блоке catch. Это даёт возможность логировать ошибку, уведомлять пользователя и продолжать работу скрипта.


<?php
declare(strict_types=1);

function sum(int $a, int $b): int {
    return $a + $b;
}

try {
    echo sum(5, 'abc'); // TypeError: Argument 2 passed to sum() must be of the type int, string given
} catch (TypeError $e) {
    echo 'Произошла ошибка типа: ' . $e->getMessage();
    // Дополнительные действия: запись в лог, отправка уведомления
}
?>
  

Php not found (ошибка 404 в php)

Проблемы и их решения:

  • Если не указать конкретный класс исключения, блок catch может перехватить лишние ошибки. Решение: указывать TypeError или Error.
  • При глубокой вложенности try-catch может усложнить код. Решение: использовать единый обработчик исключений.

Как использовать глобальный обработчик исключений вместо try-catch?

Функция set_exception_handler() позволяет задать обработчик для всех необработанных исключений, включая TypeError. Это удобно для централизованного логирования или отображения дружественной страницы ошибки.


<?php
set_exception_handler(function (Throwable $e) {
    echo 'Необработанное исключение: ' . $e->getMessage();
    // Запись в файл лога
    error_log($e->__toString());
});

declare(strict_types=1);

function divide(float $a, float $b): float {
    return $a / $b;
}

echo divide(10, 'abc'); // TypeError, будет перехвачена обработчиком
?>
  

Php try (обработка исключений try-catch в php)

Проблемы: Обработчик не может перехватить ошибки из блоков уже существующего try-catch. Решение: комбинировать оба подхода.

Как избежать TypeError с помощью проверки типов до вызова функции?

Перед передачей аргументов можно явно проверить их тип с помощью is_int(), is_string() и других функций. Если тип неверный - либо привести значение, либо выбросить собственную ошибку.


<?php
function multiply(int $x, int $y): int {
    return $x * $y;
}

$value1 = '5';
$value2 = 10;

if (is_int($value1) && is_int($value2)) {
    echo multiply($value1, $value2);
} else {
    echo 'Оба аргумента должны быть целыми числами.';
}
?>
  

Php код ответа (код ответа http в php)

Проблемы: Избыточная проверка перед каждым вызовом. Решение: использовать предварительное приведение типов с помощью (int) или intval(), но это может скрыть логические ошибки.

Как отключить строгий режим типизации, чтобы TypeError не возникала?

Убрав объявление declare(strict_types=1) или установив его в 0, PHP будет автоматически приводить типы. Однако это может привести к неожиданным результатам и скрыть ошибки проектирования.


<?php
declare(strict_types=0); // или просто не объявлять

function add(int $a, int $b): int {
    return $a + $b;
}

echo add(5, '10'); // Результат 15, строка '10' приведена к int
?>
  

Post 500 php (ошибка 500 при post-запросе в php)

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

Как использовать set_error_handler для перехвата TypeError?

Начиная с PHP 7.x, большинство ошибок (включая TypeError) выбрасываются как исключения класса Error, и обычный обработчик ошибок (set_error_handler) их не ловит. Однако можно перехватить часть ошибок раннего типа, но не TypeError напрямую. Данный способ не рекомендуется как основной.


<?php
set_error_handler(function ($severity, $message, $file, $line) {
    if (error_reporting() & $severity) {
        throw new ErrorException($message, 0, $severity, $file, $line);
    }
});
// TypeError всё равно не будет перехвачен этим обработчиком
// Для перехвата TypeError нужен set_exception_handler
?>
  
- Pdo php try (pdo php try)
- Php include try (php include с try)
- Try files php (try при работе с файлами php)

Расширенные примеры обработки TypeError в PHP

Покажем более сложные сценарии, включающие union-типы, nullable, методы классов и конструкторы.

Пример 1: Обработка TypeError с union-типами (PHP 8+)

Функция принимает int|string. Если передать array, будет TypeError.

Пример

<?php
declare(strict_types=1);

function process(int|string $input): void {
    echo "Обработан: $input";
}

try {
    process([1,2,3]); // TypeError: process(): Argument #1 ($input) must be of type int|string, array given
} catch (TypeError $e) {
    echo 'Ошибка: ' . $e->getMessage();
}
?>
Ошибка: process(): Argument #1 ($input) must be of type int|string, array given

Пример 2: TypeError в конструкторе класса

Класс с типизированными свойствами. Неправильный тип при создании объекта вызывает TypeError.

Пример

<?php
class User {
    public function __construct(
        public readonly string $name,
        public readonly int $age
    ) {}
}

try {
    $user = new User('John', 'thirty'); // TypeError: User::__construct(): Argument #2 ($age) must be of type int, string given
} catch (TypeError $e) {
    echo 'Не удалось создать пользователя: ' . $e->getMessage();
}
?>
Не удалось создать пользователя: User::__construct(): Argument #2 ($age) must be of type int, string given

Пример 3: Обработка ошибки типа при возврате значения

Функция объявлена с возвращаемым типом int, но возвращает строку. TypeError вылетает при попытке возврата.

Пример

<?php
declare(strict_types=1);

function getNumber(): int {
    return 'not a number'; // TypeError возвращается сразу
}

try {
    $num = getNumber();
} catch (TypeError $e) {
    echo 'Ошибка возвращаемого типа: ' . $e->getMessage();
}
?>
Ошибка возвращаемого типа: getNumber(): Return value must be of type int, string returned

Пример 4: Централизованная обработка с сохранением контекста

Использование set_exception_handler вместе с логированием в файл и показом пользователю понятного сообщения.

Пример

<?php
set_exception_handler(function (Throwable $e) {
    $logEntry = date('Y-m-d H:i:s') . ' - ' . $e->__toString();
    file_put_contents('error.log', $logEntry, FILE_APPEND);
    http_response_code(500);
    echo 'Произошла внутренняя ошибка. Пожалуйста, попробуйте позже.';
});

declare(strict_types=1);

function fetchData(int $id): string {
    return "Data for $id";
}

fetchData('abc'); // TypeError будет перехвачена обработчиком
?>

В файл error.log запишется полная информация об исключении, а пользователь увидит сообщение без технических деталей.

Пример 5: Использование is_* функций для безопасной передачи аргументов в класс

Перед вызовом конструктора проверяем типы и выбрасываем собственное исключение с понятным текстом.

Пример

<?php
class Rectangle {
    public function __construct(
        public readonly float $width,
        public readonly float $height
    ) {}
}

function createRectangle(mixed $w, mixed $h): ?Rectangle {
    if (!is_float($w) || !is_float($h)) {
        throw new InvalidArgumentException('Ширина и высота должны быть числами с плавающей точкой.');
    }
    return new Rectangle($w, $h);
}

try {
    $rect = createRectangle(10.5, '20.0'); // строка, будет выброшено исключение
} catch (InvalidArgumentException $e) {
    echo $e->getMessage();
}
?>
Ширина и высота должны быть числами с плавающей точкой.

Необработанная ошибка типа PHP - comments

En
Uncaught typeerror php (php)