# 08. Обработка ошибок и Result Object

[← Оглавление](./index.md)

---

## Исключения вместо возврата false/null

**ПЛОХО — СТАРЫЙ ПОДХОД BITRIX С ГЛОБАЛЬНЫМ СОСТОЯНИЕМ**
```php
$leadId = \CCrmLead::Add(['TITLE' => '']);
if (!$leadId) {
    $error = \CCrmLead::GetLastError(); // глобальное состояние
}
```

**ХОРОШО — ДОМЕННЫЕ ИСКЛЮЧЕНИЯ**
```php
class LeadCreationException extends \RuntimeException {}

try {
    $lead = $this->leadService->createFromDto($dto);
} catch (LeadCreationException $e) {
    $this->logger->error($e->getMessage());
}
```

---

## Иерархия доменных исключений

**ПЛОХО — БАЗОВЫЙ \EXCEPTION БЕЗ КОНТЕКСТА**
```php
throw new \Exception('Неверный email');
// caller не знает, какое именно исключение ловить
```

**ХОРОШО — ИЕРАРХИЯ ДОМЕННЫХ ИСКЛЮЧЕНИЙ**
```php
class MyModuleException extends \RuntimeException {}
class InvalidEmailException extends \DomainException {}
class LeadNotFoundException extends \Bitrix\Main\ObjectNotFoundException {}
class LeadValidationException extends MyModuleException {}

throw new InvalidEmailException('Email имеет неверный формат: ' . $email);
```

---

## Нативный Result Object Bitrix

Result Object — нативный паттерн Bitrix для операций уровня сервиса. Используйте его там, где нужно вернуть данные или набор ошибок без исключений.

**ПЛОХО — ВОЗВРАТ NULL ПРИ ОШИБКЕ, НЕТ ДЕТАЛЕЙ**
```php
public function create(CreateLeadDto $dto): ?int {
    $lead = $factory->createItem();
    $lead->setTitle($dto->title);
    $result = $factory->getCreateOperation($lead)->launch();
    if (!$result->isSuccess()) {
        return null; // caller не знает, что именно пошло не так
    }
    return $lead->getId();
}
```

**ХОРОШО — RESULT С ДЕТАЛЯМИ ОШИБОК**
```php
public function create(CreateLeadDto $dto): \Bitrix\Main\Result {
    $result = new \Bitrix\Main\Result();
    try {
        $factory = \Bitrix\Crm\Service\Container::getInstance()
            ->getFactory(\CCrmOwnerType::Lead);
        $lead = $factory->createItem();
        $lead->setTitle($dto->title);
        $opResult = $factory->getCreateOperation($lead)->launch();
        if (!$opResult->isSuccess()) {
            return $result->addErrors($opResult->getErrors());
        }
        $result->setData(['id' => $lead->getId()]);
    } catch (\Throwable $e) {
        $result->addError(new \Bitrix\Main\Error($e->getMessage(), $e->getCode()));
    }
    return $result;
}

// Использование:
$result = $leadService->create($dto);
if ($result->isSuccess()) {
    $leadId = $result->getData()['id'];
} else {
    foreach ($result->getErrors() as $error) {
        $logger->error($error->getMessage());
    }
}
```