Результат работы и ошибки
При разработке веб-приложений, которые выполняют не только CRUD-операции, важно правильно передавать результаты работы и ошибки.
Для передачи результата обычно используют массивы или объекты данных DTO. Ошибки передают через исключения. У такого подхода есть особенности:
-
массивы не дают типизации и контроля содержимого,
-
исключения не позволяют передать несколько ошибок сразу, например, когда при проверке данных несколько полей неверны.
Используйте объект результата \Bitrix\Main\Result для решения проблем. Он позволяет передавать данные и ошибки одновременно.
Класс \Bitrix\Main\Result
Класс Result хранит результаты операций и ошибки. Он помогает определить, прошла ли операция успешно.
Методы класса:
-
setData($data)— сохраняет данные результата, -
isSuccess()— проверяет, успешна ли операция, -
getError()— возвращает первую ошибку, -
getErrors()— возвращает ошибки, -
getErrorMessages()— получает сообщения об ошибках, -
getErrorCollection()— возвращает коллекцию ошибок, -
getData()— получает данные результата, -
addErrors(array $errors)— добавляет несколько ошибок, -
addError(Error $error)— добавляет одну ошибку.
Пример использования Result
Функция updateUserData проверяет идентификатор пользователя, обновляет данные и возвращает результат.
-
Если идентификатор пользователя неверный, добавляется ошибка.
-
Если обновление не удалось, добавляется другая ошибка.
-
При успешном выполнении сохраняются обновленные данные.
use Bitrix\Main\Result;
use Bitrix\Main\Error;
function updateUserData(int $userId, array $fields): Result
{
$result = new Result();
if ($userId <= 0) {
$result->addError(new Error('Неверный ID пользователя', 'INVALID_USER_ID'));
return $result;
}
// Обновляем данные
$updateResult = someUpdateFunction($userId, $fields);
if ($updateResult === false) {
$result->addError(new Error('Ошибка при обновлении данных', 'UPDATE_FAILED'));
} else {
$result->setData(['UPDATED_FIELDS' => $fields]);
}
return $result;
}
// Используем функцию
$result = updateUserData(123, ['NAME' => 'Иван', 'LAST_NAME' => 'Иванов']);
if ($result->isSuccess()) {
$data = $result->getData();
echo 'Данные обновлены: ' . print_r($data, true);
} else {
$errors = $result->getErrorMessages();
echo 'Ошибки: ' . implode(', ', $errors);
}
Типизация данных
По умолчанию данные представлены в виде обычного массива. Отсутствие строгой типизации может привести к проблемам.
Если нужно передать большой объем данных, создайте класс-наследник от объекта результата. Используйте свойства и методы get, set, чтобы добавить в объект конкретные и типизированные данные.
use Bitrix\Main\Result;
use Bitrix\Main\Error;
use Bitrix\Main\Type\DateTime;
class UserUpdateResult extends Result
{
private array $updatedFields = [];
private ?DateTime $timestamp = null;
public function setUpdatedData(array $fields, DateTime $timestamp): void
{
$this->updatedFields = $fields;
$this->timestamp = $timestamp;
}
public function getUpdatedFields(): array
{
return $this->updatedFields;
}
public function getTimestamp(): ?DateTime
{
return $this->timestamp;
}
}
function updateUserInDatabase(int $userId, array $fields): array
{
return ['ID' => $userId, ...$fields];
}
function updateUserWithTypedResult(int $userId, array $fields): UserUpdateResult
{
$result = new UserUpdateResult();
if ($userId <= 0)
{
$result->addError(new Error('Invalid user ID', 100));
return $result;
}
try {
$updatedData = updateUserInDatabase($userId, $fields);
$result->setUpdatedData(
$updatedData,
new DateTime()
);
} catch (Exception $e) {
$result->addError(new Error($e->getMessage(), $e->getCode()));
}
return $result;
}
$typedResult = updateUserWithTypedResult(123, ['NAME' => 'Иван']);
if ($typedResult->isSuccess()) {
$fields = $typedResult->getUpdatedFields();
$time = $typedResult->getTimestamp()->format('Y-m-d H:i:s');
echo 'Данные обновлены. Поля: ' . print_r($fields, true) . ', Время: ' . $time;
}
else {
echo 'Ошибки: ' . implode(', ', $typedResult->getErrorMessages());
}
Класс \Bitrix\Main\ErrorCollection
Класс ErrorCollection внутри объекта Result собирает ошибки и управляет ими. При необходимости можно работать с этой коллекцией напрямую.
Методы класса:
-
add(array $errors)— добавляет ошибки, -
getErrorByCode($code)— получает ошибку по коду, -
setError(Error $error)— добавляет одну ошибку.
Пример работы с ErrorCollection
В примере создана коллекция и в нее добавлено две ошибки. Затем получена вторая ошибка и выведены все ошибки.
use Bitrix\Main\ErrorCollection;
use Bitrix\Main\Error;
$errorCollection = new ErrorCollection();
// Добавляем ошибки
$errorCollection->add([
new Error('Первая ошибка', 'ERROR_1'),
new Error('Вторая ошибка', 'ERROR_2')
]);
// Добавляем ошибку по одному
$errorCollection->setError(new Error('Третья ошибка', 'ERROR_3'));
// Получаем ошибку по коду
$error = $errorCollection->getErrorByCode('ERROR_2');
if ($error) {
echo 'Найдена ошибка: ' . $error->getMessage();
}
// Перебираем ошибки
foreach ($errorCollection as $error) {
echo 'Код: ' . $error->getCode() . ', Сообщение: ' . $error->getMessage() . '<br>';
}
Практические рекомендации
-
Проверяйте
isSuccess()перед получением данных. -
Используйте коды ошибок для их идентификации.
-
Группируйте ошибки в
ErrorCollection. -
Записывайте ошибки в логи при необходимости.
-
Используйте понятные сообщения об ошибках для пользователей. Технические детали оставляйте в кодах ошибок.