# 03. Классы и объекты (SOLID, DI, ServiceLocator)
[← Оглавление](./index.md)
---
## Принцип единственной ответственности (SRP)
**ПЛОХО — КЛАСС ДЕЛАЕТ ВСЁ СРАЗУ**
```php
class LeadManager {
public function create(array $data): void { /* ... */ }
public function sendEmail(string $message): void { /* ... */ }
public function log(string $action): void { /* ... */ }
}
```
**ХОРОШО — РАЗДЕЛЕНИЕ ОТВЕТСТВЕННОСТЕЙ**
```php
class LeadCreationService {
public function __construct(
private \Bitrix\Crm\Service\Container $crmContainer,
private LeadNotificationService $notificationService,
private \Psr\Log\LoggerInterface $logger,
) {}
public function createFromArray(array $data): \Bitrix\Crm\Item {
// только логика создания лида
}
}
```
---
## Предпочитайте композицию наследованию
**ПЛОХО — НАСЛЕДОВАНИЕ ОТ УСТАРЕВШЕГО КЛАССА**
```php
class CustomDealProcessor extends \CCrmDeal {
public function process($dealId) {
$this->Update($dealId, ['STAGE_ID' => 'WON']);
}
}
```
**ПРАВИЛЬНО — ЧЕРЕЗ CONTAINER**
```php
class DealProcessor {
public function __construct(
private \Bitrix\Crm\Service\Container $container,
) {}
public function markAsWon(int $dealId): void {
$factory = $this->container->getFactory(\CCrmOwnerType::Deal);
$deal = $factory->getItem($dealId);
if ($deal === null) {
throw new \Bitrix\Main\ObjectNotFoundException("Deal #{$dealId} not found");
}
$deal->setStageId('WON');
$result = $factory->getUpdateOperation($deal)->launch();
if (!$result->isSuccess()) {
throw new \RuntimeException(implode(', ', $result->getErrorMessages()));
}
}
}
```
---
## ServiceLocator Bitrix для внедрения зависимостей
**ПЛОХО — РУЧНОЕ СОЗДАНИЕ ЗАВИСИМОСТЕЙ ПОВСЮДУ**
```php
// В каждом месте использования:
$logger = new FileLogger('/local/logs/app.log');
$factory = \Bitrix\Crm\Service\Container::getInstance()
->getFactory(\CCrmOwnerType::Lead);
$service = new LeadCreationService($factory, new LeadNotificationService(), $logger);
```
**ХОРОШО — РЕГИСТРАЦИЯ ОДИН РАЗ, ПОЛУЧЕНИЕ ВЕЗДЕ**
```php
use Bitrix\Main\DI\ServiceLocator;
// Один раз:
$serviceLocator = ServiceLocator::getInstance();
$serviceLocator->addInstanceLazy(
LeadCreationService::class,
static function () use ($serviceLocator): LeadCreationService {
return new LeadCreationService(
\Bitrix\Crm\Service\Container::getInstance(),
$serviceLocator->get(LeadNotificationService::class),
$serviceLocator->get(\Psr\Log\LoggerInterface::class),
);
}
);
// Получение в любом месте приложения:
$service = ServiceLocator::getInstance()->get(LeadCreationService::class);
```
---
## Избегайте статических методов для бизнес-логики
**ПЛОХО — ПРЯМОЙ ВЫЗОВ УСТАРЕВШЕГО API**
```php
$leadId = \CCrmLead::Add(['TITLE' => 'Новый лид']);
```
**ХОРОШО — ОБОРАЧИВАЕМ В СЕРВИС**
```php
class LeadService {
public function __construct(private \Bitrix\Crm\Service\Factory $factory) {}
public function create(string $title): \Bitrix\Crm\Item {
$lead = $this->factory->createItem();
$lead->setTitle($title);
return $this->factory->getCreateOperation($lead)->launch()->getItem();
}
}
```