Иногда одна единственная идея способна изменить все представление о программировании. Для меня одной из такой идей была идея сервис-контейнера. Это как золотой грааль). Вообще-то, идея не сугубо Symfony framework, это просто один из удачных паттернов проектирования приложений, часто используемый в Symfony.

В двух словах и на пальцах: сервис-ориентированая архитектура позволяет регистрировать класс (сервис), который можно будет достать с любого места приложения, зная идентификатор. То есть, говорим: “Контейнер, а дай нам такой-то сервис”, и получаем пригодный для использования объект.

Но, имхо, гениальна не так сама идея сервис контейнера, как Dependency Injection (внедрение зависимости).

Попробуем объяснить, что это такое.

Представьте себе ситуацию, что у вас есть класс, объект которого не может работать самостоятельно – для его работы нужны другие объекты (если вы считаете такую ситуацию маловероятной или ненужной – прочитайте эту заметку немного позже =))

Dependency Injection позволяет разрешить эти зависимости. Другими словами, мы можем не просто сказать “Контейнер, а дай нам такой-то сервис”, а “Контейнер, а дай нам такой-то сервис со всеми необходимыми зависимостями”.  Сервис будет зависим от других сервисов, но внешне мы об этом даже не будем догадываться.

Перейдем к практике.

Чтобы получить сервис с контроллера, достаточно вызвать:

class HelloController extends Controller
{
    // ...

public function sendEmailAction() { // … $mailer = $this->get(‘my_mailer’); $mailer->send(‘ryan@foobar.net’, …); } }

В Symfony framework  конфигурация сервиса может осуществляться в разных форматах (yml, xml, php), в примерах будем использовать yml:

# app/config/config.yml
services:
    my_mailer:
        class:        AcmeHelloBundleMailer
        arguments:    [sendmail]

Естественно, сервисы можно использовать не только в контроллере. Хорошим тоном будет не инжектить весь контейнер в сервис (речь идет о зависимостях), а только заинжектить необходимый сервис.

Например, если есть два сервисы, один может быть внедрен в другой:

# app/config/config.yml
services:
    service_foo:
        class:        AcmeHelloBundleSomeFeatureFoo
        arguments:    [@service_goo]
    service_goo:
        class:        AcmeHelloBundleSomeFeatureGoo

Если теперь вызвать в контроллере

$mailer = $this->get('service_foo');

, то получим экземпляр Foo с уже заинжектеным Goo. arguments – то, что передадим в конструктор. Пример классов:

<?php

namespace AcmeHelloBundleSomeFeature

class Foo { private $goo;

public function __construct(Goo $goo) { $this->goo = $goo } }

<?php

namespace AcmeHelloBundleSomeFeature

class Goo {

}

Осуществлять Dependency Injection можно не только через конструктор, но и с помощью сеттера. Модифицируем предыдущий пример:

# app/config/config.yml
services:
    service_foo:
        class:        AcmeHelloBundleSomeFeatureFoo
        calls:    
            - [setGoo, ["@service_goo"]]
    service_goo:
        class:        AcmeHelloBundleSomeFeatureGoo
<?php

namespace AcmeHelloBundleSomeFeature

class Foo { private $goo;

public function setGoo(Goo $goo) { $this->goo = $goo } }

Похожим образом можно инжектить и параметры, только вместо символа @ использовать “окружение” символом % с обеих сторон :

# app/config/config.yml
parameters:
    my_mailer.class:      AcmeHelloBundleMailer
    my_mailer.transport:  sendmail

services: my_mailer: class: “%my_mailer.class%” arguments: [“%my_mailer.transport%”]


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Любишь мемасики?

Подпишись на мой телеграм-канал!

Открыть
Закрыть