D7 в отличие от старого API активно использует исключения
для сигнализации об ошибках — вместо возврата false
или пустого значения, метод выбрасывает объект исключения
с описанием проблемы. Разберём иерархию исключений D7 и как
правильно их обрабатывать.
Базовая иерархия исключений D7
Exception (стандартный PHP)
└── Bitrix\Main\SystemException
├── Bitrix\Main\ArgumentException
│ ├── ArgumentNullException
│ ├── ArgumentOutOfRangeException
│ └── ArgumentTypeException
├── Bitrix\Main\NotSupportedException
├── Bitrix\Main\ObjectNotFoundException
└── Bitrix\Main\DB\SqlQueryException
Все специфичные для D7 исключения наследуются от
SystemException, что позволяет либо перехватывать
конкретный тип для точечной обработки, либо ловить общий базовый
класс, если детализация причины не важна для конкретного места
кода.
Перехват конкретного типа исключения
<?php
use Bitrix\Main\ArgumentException;
use Bitrix\Main\ObjectNotFoundException;
try {
$result = someD7Method($params);
} catch (ArgumentException $e) {
// некорректные входные параметры — ошибка на стороне вызывающего кода
AddMessage2Log('Invalid argument: ' . $e->getMessage(), 'my.module');
} catch (ObjectNotFoundException $e) {
// запрошенный объект не найден — ожидаемая ситуация, не критичная ошибка
return null;
}
Раздельная обработка разных типов исключений позволяет реагировать по-разному на разные причины сбоя — некорректный аргумент часто указывает на баг в вызывающем коде и заслуживает логирования, тогда как "объект не найден" может быть штатной, ожидаемой ситуацией, не требующей тревожного лога.
Нужна помощь с Битрикс?
Собственные исключения проекта
<?php
namespace Vendor\Module\Exception;
use Bitrix\Main\SystemException;
class InsufficientStockException extends SystemException
{
public function __construct(int $productId, int $requested, int $available)
{
parent::__construct(
"Недостаточно остатка для товара {$productId}: запрошено {$requested}, доступно {$available}"
);
}
}
Наследование от SystemException для собственных
исключений проекта делает их частью общей иерархии D7 — код,
ловящий базовый SystemException где-то выше по стеку
вызовов, автоматически перехватит и кастомное исключение проекта,
а не только штатные исключения ядра.
Исключения при работе с базой данных
<?php
use Bitrix\Main\DB\SqlQueryException;
use Bitrix\Main\Application;
try {
$connection = Application::getConnection();
$connection->query('SELECT * FROM nonexistent_table');
} catch (SqlQueryException $e) {
AddMessage2Log('SQL error: ' . $e->getMessage(), 'my.module');
}
Ошибки SQL-запросов через D7-обёртку подключения к базе тоже
выбрасываются как исключения, а не возвращаются кодом ошибки, —
это отличается от старого API с глобальным $DB,
где ошибки часто нужно проверять через отдельный метод после
выполнения запроса.
Смешение старого API и исключений D7
Код, вызывающий методы старого API (возвращающие
false при ошибке) внутри try/catch, рассчитанного
на перехват исключений D7, не получит ожидаемого поведения —
старый API не выбрасывает исключений, поэтому его ошибки нужно
проверять привычным способом через возвращаемое значение,
а не try/catch, даже если этот код физически расположен рядом
с D7-вызовами в одном методе.
Необработанное исключение и белый экран
Исключение, не перехваченное нигде по всей цепочке вызовов, доходит до глобального обработчика PHP и, в зависимости от настроек отображения ошибок, либо показывает белый экран, либо полную трассировку с чувствительной информацией о структуре кода и сервера. На боевом сайте вывод трассировки исключений для посетителя должен быть отключён — критичные ошибки логируются, а не показываются публично.
Частые ошибки
- Перехватывается только общий SystemException без разбора причины. Теряется возможность по-разному реагировать на разные типы ошибок.
- Код старого API обёрнут в try/catch как если бы он выбрасывал исключения. Реальная ошибка остаётся непойманной, поскольку старый API возвращает false, а не выбрасывает исключение.
- Трассировка необработанного исключения видна публично на проде. Утечка чувствительной информации о структуре кода и сервера.
Итог
D7 последовательно использует исключения для сигнализации
об ошибках, выстроенные в общую иерархию от базового
SystemException — собственные исключения проекта
стоит наследовать от того же базового класса для единообразной
обработки. Важно помнить, что старый API продолжает работать
через возвращаемые значения, а не исключения, что требует разного
подхода к обработке ошибок в коде, смешивающем оба API.
