0

Если вы хотите иметь другой промежуточный слой/объект в промежуточном программном вы должны использовать завод какZend Выразительный Dependency Injection

namespace App\Somnething; 
use Interop\Container\ContainerInterface; 
class MyMiddlewareFactory 
{ 
    public function __invoke(ContainerInterface $container, $requestedName) 
    { 
     return new $requestedName(
      $container->get(\App\Path\To\My\Middleware::class) 
     ); 
    } 
} 

Так MyMiddleware бы вводили \App\Path\To\My\Middleware, и мы могли бы получить к нему доступ ,

Вопрос: Неправильно ли вводить промежуточное программное обеспечение с самим приложением или контейнером? Вроде:

namespace App\Somnething; 
use Interop\Container\ContainerInterface; 
use Zend\Expressive\Application; 
class MyMiddlewareFactory 
{ 
    public function __invoke(ContainerInterface $container, $requestedName) 
    { 
     return new $requestedName(
      $container->get(Application::class) 
     ); 
    } 
} 

Таким образом можно было бы получить что-нибудь ~ на лету. Как

namespace App\Somnething; 
use Zend\Expressive\Application; 
class MyMiddleware 
{ 
    /** @var Application $app */ 
    protected $app; 

    public function __construct(Application $app) 
    { 
     $this->app = $app; 
    } 

    public function __invoke($some, $thing) 
    { 
     if ($some and $thing) { 
      $ever = $this->app 
       ->getContainer() 
       ->get(\Path\To\What\Ever::class); 
      $ever->doSome(); 
     } 
    } 
} 

ответ

4

Вы не вводят связующее ПО в другое ПО промежуточного слоя. Вы добавляете зависимости, такие как службы или репозитории. Каждое промежуточное программное обеспечение выполняет определенную задачу, такую ​​как аутентификация, авторизация, согласование локализации и т. Д. Они выполняются один за другим. Они возились с запросом и передавали запрос на следующее промежуточное программное обеспечение. После того, как стек промежуточного программного обеспечения был исчерпан, ответ возвращается полностью назад через все промежуточное ПО в обратном порядке, пока он, наконец, не достигнет внешнего уровня, который отображает вывод. Обзор потока можно найти в expressive docs.

Я бы не советовал вводить контейнер и, конечно же, не сам приложение. Хотя это может быть легко во время разработки, ваше приложение становится нецелесообразным. Если вы вводите только те сервисы, которые необходимы для промежуточного программного обеспечения, действия или службы, вы можете легко имитировать их во время тестов. Через некоторое время вы привыкли писать фабрики там, где это необходимо, и это происходит довольно быстро.

То же самое касается инъекции менеджера сущности (если вы используете доктрину). Тестировать приложение проще, если вы только вводите необходимые репозитории, которые вы можете легко высмеять.

Сказав это, если вы ищете простой способ введения зависимостей, zend-servicemanager может это сделать. Взгляните на abstract factories. С абстрактной фабрики вы можете создать один завод для всех классов действий:

<?php 

namespace App\Action; 

use Interop\Container\ContainerInterface; 
use ReflectionClass; 
use Zend\ServiceManager\Factory\AbstractFactoryInterface; 

class AbstractActionFactory implements AbstractFactoryInterface 
{ 
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null) 
    { 
     // Construct a new ReflectionClass object for the requested action 
     $reflection = new ReflectionClass($requestedName); 
     // Get the constructor 
     $constructor = $reflection->getConstructor(); 
     if (is_null($constructor)) { 
      // There is no constructor, just return a new class 
      return new $requestedName; 
     } 

     // Get the parameters 
     $parameters = $constructor->getParameters(); 
     $dependencies = []; 
     foreach ($parameters as $parameter) { 
      // Get the parameter class 
      $class = $parameter->getClass(); 
      // Get the class from the container 
      $dependencies[] = $container->get($class->getName()); 
     } 

     // Return the requested class and inject its dependencies 
     return $reflection->newInstanceArgs($dependencies); 
    } 

    public function canCreate(ContainerInterface $container, $requestedName) 
    { 
     // Only accept Action classes 
     if (substr($requestedName, -6) == 'Action') { 
      return true; 
     } 

     return false; 
    } 
} 

Я написал blog post об этом.

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

+0

Не было бы лучше реализовать промежуточное ПО «MiddlewareInterface» и позволить ':: canCreate' проверять, если' return in_array ('MiddlewareInterface', class_implements ($ requestName), true); 'Спасибо btw! – cottton

+0

Это также возможно. Однако, насколько мне известно, очень дорого использовать Reflection. Я не хочу, чтобы авто инициализировать все мое промежуточное ПО, для меня достаточно всего 1 класса действия за запрос. – xtreamwayz

0

Инъекционного приложение или контейнер в вашем промежуточном слое возможно, но это не хорошая идея вообще:

1) Инверсия управления (IoC)

Он нарушил инверсию принципа управления, ваш класс не должен иметь никаких знаний о контейнере IoC.

2) Принцип инверсии зависимостей (DIP)

Dependency принцип инверсия утверждает, что «модули высокого уровня не должны зависеть от модулей низкого уровня», так что ваш высший класс уровня промежуточного слоя зависит от инфраструктуры/рамок ,

3) Закон Деметры (LOD)

Согласно закону Деметры, блок должен иметь ограниченные знания о других единицах, он должен знать только о своих тесно связанных единиц.

MyMiddleware::class имеет слишком много знаний и другие подразделения, в первую очередь, он знает о Application::class, то он знает, что Application знает о Container, то он знает, что Container знает о What\Ever::class и так далее.

Этот вид кода нарушает некоторые из важнейших принципов ООП, ведет к ужасной связи с каркасом, имеет неявные зависимости и наименьший, но не последний, его трудно читать и понимать.