Silex: как подключить несколько сторонних библиотек?

1

Я пытаюсь внедрить сторонний инструмент в свой пользовательский класс в Silex. Затем я планирую заменить этот инструмент другой библиотекой в какой-то момент. Чтобы соответствовать принципам DI, чтобы разделить мой класс и библиотеки, я собираюсь указать интерфейс, который должны реализовать эти инструменты. И введите hint интерфейс в свой собственный конструктор классов. Это поможет мне избежать любых изменений в моем классе. Как это

class MyCustomClass 
{
    private $tool;

    public function __construct(MyCustomInterface $tool)
    {
        $this->tool = $tool;
    }
}

Чтобы зарегистрировать эти сторонние библиотеки, мне нужно создать поставщика услуг для каждого из них. Тогда мне кажется, что мне нужны какие-то адаптеры, чтобы эти инструменты соответствовали состояниям MyCustomInterface контракта. Оказывается, для каждого стороннего инструмента я должен управлять двумя дополнительными классами (провайдером и адаптером).

Мои вопросы:

  • Я полностью ли понял концепцию DI?

  • Можно ли упростить это решение?

  • Может ли Silex справиться с этой ситуацией с помощью "адаптеров"?

Теги:
dependency-injection
silex

1 ответ

1
Лучший ответ

Насколько я могу судить, вы правильно поняли концепцию DI. Если вы не хотите реорганизовывать весь свой код (ну, код, который использует вашу библиотеку) каждый раз, когда вы меняете свою библиотеку, тогда адаптер - это путь: вы определяете конкретный API с интерфейсом, который должен реализовать каждый адаптер. Таким образом, вы можете безопасно вызывать методы интерфейса без каких-либо знаний о реализации. Итак, IMHO - это путь, вы снова здесь (но я думаю, что ваше решение в контексте Silex может быть упрощено, и да, Silex может справиться с этим, любые другие современные рамки должны также).

Чтобы упростить предлагаемое решение, я бы не создавал другого поставщика для каждой реализации. Поставщик - это то, что связывает вашу библиотеку с Silex, вам просто нужно сообщить провайдеру, какой адаптер (реализация) должен использовать, и вы можете сделать это с помощью параметра (см. Примечание в конце примера кода). Поэтому я бы пошел с чем-то вроде этого:

<?php

namespace Acme;

use Silex\Application;
use Silex\ServiceProviderInterface;
use Acme\MyCustomInterface; // This is your library interface

class MyCustomLibraryServiceProvider implements ServiceProviderInterface
{
    public function register(Application $app)
    {
        $app['some_dependency'] = $app->protect(function() use ($app) {
           // do whatever to create a new instance of this dependency
        });

        $app['another_dependency'] = $app->protect(function() use ($app) {
           // do whatever to create a new instance of this dependency
        });

        $app['my_service'] = $app->protect(function () use ($app) {
            // assuming your adapter has 2 dependencies.
            $myService = new $app['my_service_class']($app['some_dependency'], $app['another_dependency']);

            if (!$myService instanceof MyCustomInterface) {
                throw new \RuntimeException("The 'my_service_class' parameter must implement MyCustomInterface!");
            }

            return $myService;
        });
    }

    public function boot(Application $app)
    {
    }
}

Затем, когда вы создаете свой экземпляр $ app (вы можете создать столько адаптеров, сколько хотите):

<?php
//...
use Acme\MyCustomLibraryServiceProvider;

//...
$app->register(new MyCustomLibraryServiceProvider(), [
    'my_service_class' => "Acme\MyCustomLibraryAdapter1"
]);

Обратите внимание, что это решение предполагает, что каждый адаптер будет иметь одинаковые зависимости. Если это не так, вам нужно создать другого поставщика для каждого адаптера, но если вы этого не хотите, продолжайте читать :-)

Если вы хотите еще больше упростить это, учтите, что вам вообще не нужно создавать провайдера. Если ваша библиотека не имеет зависимостей или имеет только 1 или 2, вы можете создать свою службу непосредственно в том же файле, где вы создаете экземпляр вашего приложения (IMHO поставщик полезен, если код для создания вашего сервиса тяжелый):

<?php
//...
use Silex\Application;
use Acme\MyCustomLibraryAdapter1;

$app = new Application();
//...
$app['my_service'] = $app->protect(function() use ($app) {
  $dep1 = new WhatEver();

  return new MyCustomLibraryAdapter1($dep1);
});

Это решение менее элегантно, но проще (вам нужно изменить код, который создает ваш сервис для каждого адаптера).

  • 0
    Большое спасибо за этот описательный ответ. Вы дали мне идею объединить всю логику с этими адаптерами в провайдера. Это хорошо, я никогда не думал об этом. Я определенно буду использовать это!
  • 0
    ИМХО, для этого и нужны провайдеры Silex (хорошо Pimple) :-)
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню