DI в DDD проектах

Обсуждаем, как правильно строить приложения
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

ElisDN писал(а): 2017.04.19, 15:10
zelenin писал(а): 2017.04.19, 14:46 ElisDn, а вообще сторонние DIC позволяют резолвить зависимости, которые в них явно не прописаны? это как-то противоречит самому названию dependency injection container.
В Yii, PHP-DI и Laravel такой autowiring включен по умолчанию.

В Symfony можно включить опцией autowire у любого сервиса, и контейнер тоже начнёт рекурсивно парсить конструкторы и создавать всё в лоб через new, если не найдёт определений для нужного класса.
ну и оно разные инстансы создает или один?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI в DDD проектах

Сообщение ElisDN »

zelenin писал(а): 2017.04.19, 15:22 ну и оно разные инстансы создает или один?
В Symfony логика такая:
...the subsystem is smart enough to automatically register a private service for the class...
В Symfony все сервисы shared по умолчанию. При автосоздании сервиса shared не отключается. Значит один инстанс.
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

Небольшой пример реализации вышеописанного примера с PHP-DI:

Код: Выделить всё


class Foo {
    public function __construct()
    {
        echo "Foo", PHP_EOL;
    }

}

class Bar {
    public function __construct(Foo $foo)
    {

    }
}

class Hoo {
    public function __construct(Foo $foo, Bar $bar)
    {

    }
}

$builder = new DI\ContainerBuilder();
$container = $builder->build();

$instance1 = $container->get(Hoo::class);
$instance2 = $container->get(Hoo::class);

var_dump($instance1 === $instance2);
Foo и Hoo будут созданы один раз и будут переиспользоваться
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI в DDD проектах

Сообщение ElisDN »

Значит в Symfony и PHP-DI даже с autowiring по умолчанию идёт один инстанс, что логично для контейнера $container->get(...). Для возврата новых инстансов нужно вручную отключать shared=false или объявлять фабрику.

В Yii, наоборот, для всего по умолчанию создаются новые инстансы, что логично для фабрики Yii::createObject(...). А общие сервисы нужно форсированно шарить через setSingleton(...).
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

и тут они как раз поменялись местами - symfony/php-di выступают с позиции "быстрой разработки", а yii поступает более канонично и правильно (в ущерб rad).
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI в DDD проектах

Сообщение ElisDN »

zelenin писал(а): 2017.04.19, 15:52 а yii поступает более канонично и правильно
Ну если насчёт shared или не shared по умолчанию, то предпочитаю наоборот всё в shared.

Более склоняюсь к использованию контейнера именно как контейнера stateless сервисов-синглтонов c $container->get($id), а не как фабрику для клепания на лету новых инстансов по примеру Yii. В возврате новых инстансов для таких сервисов нет смысла. А если нужно клепать динамически инстансы как в фабрике, то и инъектим саму фабрику-синглтон и клепаем через $this->factory->create($params).
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: DI в DDD проектах

Сообщение slavcodev »

ElisDN писал(а): 2017.04.19, 16:20 Более склоняюсь к использованию контейнера именно как контейнера stateless сервисов-синглтонов c $container->get($id), а не как фабрику для клепания на лету новых инстансов по примеру Yii. В возврате новых инстансов для таких сервисов нет смысла. А если нужно клепать динамически инстансы как в фабрике, то и инъектим саму фабрику-синглтон и клепаем через $this->factory->create($params).
Да, я тоже считаю что "контейнер" для хранение stateless-сервисов а не для создания сервисов с разными состояниями.
Жду Yii 3!
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

А кто какой DI контейнер использует в проектах на Yii? и как вы его интегрируете c Yii (если используете сторонний)?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI в DDD проектах

Сообщение ElisDN »

glagola писал(а): 2017.04.20, 23:36 А кто какой DI контейнер использует в проектах на Yii?
Встроенный Yii::$container.
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DI в DDD проектах

Сообщение anton_z »

glagola писал(а): 2017.04.20, 23:36 А кто какой DI контейнер использует в проектах на Yii? и как вы его интегрируете c Yii (если используете сторонний)?
Мы рефакторим проект на первом Yii, прикрутили zend-servicemanager от zf3. Очень простой и быстрый контейнер, построенный на фабриках. Поддерживает PSR. Зависимости запрашиваем в контроллере в первых строках экшенов и больше нигде. Это самая высокая точка для запроса зависимостей, которую предоставляет первый yii. Была бы какая-нибудь фабрика контроллеров, которую можно было бы подменить, инжектили бы через конструктор или методы экшенов.

Код: Выделить всё


/** @var Psr\ContainerInterface */
$cnt = \Yii::app()->getComponent('container');
$service = $cnt->get(SomeService::class);

А дальше сервисы работают через внедрение конструктора. То есть в контроллере резолвится граф зависимостей.
Минусы - много фабрик писать, но зато они простые.
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: DI в DDD проектах

Сообщение slavcodev »

anton_z писал(а): 2017.04.21, 02:41 Зависимости запрашиваем в контроллере в первых строках экшенов и больше нигде.
Я тоже Yii проект поддерживаю, зависимости инжектятся в экшн.

Код: Выделить всё

    public function actionPut(SchedulePayment $command, LoadPayment $query, $paymentId)
    {
        $validator = new PaymentValidator();
        $data = $this->loadIncomingData($validator);

        $command->handle($paymentId, $data);

        $payment = $query->loadPayment($paymentId);

        if ($payment->isCompleted()) {
            $this->sendLocationHeader(['paymentId' => $paymentId], 'get');
            $this->sendResponse($payment, HttpStatus::REQUEST_CREATED);
        } else {
            $this->sendLocationHeader(['paymentId' => $paymentId], 'getQueued');
            $this->sendResponse($payment, HttpStatus::REQUEST_ACCEPTED);
        }
    }
   
    /**
     * Returns params used to action binding.
     * Uses union of services dependencies and $_GET.
     *
     * List of dependencies MUST be a priority and should be used first.
     *
     * {@inheritdoc}
     */
    public function getActionParams()
    {
        return $this->getActionDependencies() + parent::getActionParams();
    }
Жду Yii 3!
Ответить