0

당신은 그래서 MyMiddleware\App\Path\To\My\Middleware 주입했을젠드 표현 의존성 주입

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) 
     ); 
    } 
} 

같은 공장을 사용해야 미들웨어의 다른 미들웨어/객체를 갖고 싶어하고 우리는 그것을 액세스 할 수있을 것입니다 경우 .

질문 : 미들웨어에 응용 프로그램 자체 또는 컨테이너를 주입하는 것이 좋지 않습니까? Like :

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) 
     ); 
    } 
} 

이렇게하면 비행 중에도 아무 것도 얻을 수 없습니다. Like

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에서 흐름 개요를 찾을 수 있습니다.

컨테이너를 주입하는 것은 좋지만 앱 자체는 주입하지 않는 것이 좋습니다. 개발 중에는 쉽지만 응용 프로그램은 테스트 할 수 없게됩니다. 미들웨어, 행동 또는 서비스에 필요한 서비스 만 주입하면 테스트 중에 쉽게 위조 할 수 있습니다. 잠시 후에 필요한 곳에 공장을 쓰는 데 익숙해지면 꽤 빨리 진행됩니다.

엔티티 관리자를 삽입 할 때도 마찬가지입니다 (doctrine을 사용하는 경우). 필요한 저장소 만 주입하면 응용 프로그램을 테스트하는 것이 더 쉽습니다.이 저장소는 쉽게 모의 할 수 있습니다.

이렇게 말한 후 종속성을 주입하기 쉬운 방법을 찾고 있다면 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'에 의해 액션 미들웨어를 구현하는 것이 더 좋을 것이고'return in_array ('MiddlewareInterface', class_implements ($ requestedName), true);가''can check '! – cottton

+0

그럴 수도 있습니다. 그러나 내가 아는 한 Reflection을 사용하는 것은 매우 비쌉니다. 자동으로 모든 미들웨어를 초기화하고 싶지는 않습니다. 요청 당 1 액션 클래스 만 있으면 충분합니다. – xtreamwayz

0

미들웨어에서 응용 프로그램 또는 컨테이너를 주입하는 것은 가능하지만 전혀 좋은 생각이 아니다 : 그것은 제어 원리의 반전을 위반

)

1) 제어의 역전 (IoC에 당신의 클래스는 IoC 컨테이너에 대한 지식이 없어야합니다.

2) 의존 관계 역전 원칙 (DIP)

종속성 반전 원리는 그래서 당신의 높은 수준의 미들웨어 클래스는 인프라/프레임 워크에 따라, "높은 수준의 모듈은 낮은 수준의 모듈에 의존하지해야한다"고 주장한다 .

3) 데메테르의 법칙 LOD (가)

데메테르의 법칙에 따르면, 장치가 다른 장치에 대한 제한된 지식을 가지고 있어야, 그것은 단지 그 밀접하게 관련 단위에 대해 알아야한다.

MyMiddleware::class 그것은 다음은 ApplicationContainer에 대해 알고있는 것을 알고 다음은 Container가 등등 What\Ever::class 및 대해 알고있는 것을 알고는 Application::class에 대해 알고, 무엇보다도 너무 많은 지식을 다른 유닛을 가지고 있습니다.

이러한 종류의 코드는 가장 중요한 OOP 원칙 중 일부를 위반하고 프레임 워크와 끔찍한 연관성을 갖게되며 암시 적 종속성을 가지며 최소한이지만 최하위가 아니기 때문에 읽고 이해하기 어렵습니다.