应用程序中的每个对象的PHP DI / IoC容器配置还是?

时间:2015-05-14 07:33:57

标签: php dependency-injection ioc-container

我有一个问题:我是否需要为应用程序中的每个对象配置DI / IoC容器或只配置工厂?

现在我有这样的事情:

'serviceFactory' => function() use ($container) {
    return new \Application\Core\Factory\ServiceFactory($container->get('entityFactory'), $container->get('repositoryFactory'), $container->get('cache'), $container->get('file'), $container->get('image'));
},

'repositoryFactory' => function() use ($container) {
    return new \Application\Core\Factory\RepositoryFactory($container->get('database'), $container->get('queryBuilder'), $container->get('mapper'), $container->get('language'));
},

'entityFactory' => function() use ($container) {
    return new \Application\Core\Factory\EntityFactory($container->get('language'));
},

但是,应用程序会将不必要的对象加载到其他不需要的对象中。

示例:在 BlogService 中,我不使用文件类或图像类。在 ThumbnailService 我这样做,但我不在其中使用实体存储库

那么,我是否需要在DI / IoC容器中导入一些延迟加载,或者我需要像这样编写每个Entity / Repository / Service / Controller连接:

'blogController' => function() use ($container) {
    return new \Application\Controller\BlogController($container->get('blogService'));
},

'blogService' => function() use ($container) {
    return new \Application\Service\BlogService($container->get('blog'), $container->get('categoryEntity'), $container->get('blogRepository'), $container->get('cache'));
},

'blogRepository' => function() use ($container) {
    return new \Application\Model\Repository\BlogRepository($container->get('database'), $container->get('queryBuilder'), $container->get('mapper'), $container->get('language'));
},

'blog' => function() use ($container) {
    return new \Application\Model\Entity\Blog($container->get('language'));
},

'thumbnailService' => function() use ($container) {
    return new \Application\Service\ThumbnailService($container->get('image'), $container->get('file'));
},

但是这样我可以编写所有50-100个实体,存储库,服务和控制器,可能会过度优化?

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

不,通常您只需要注册可以变化的类型,即抽象的具体实现。如果你没有使用抽象,那么DI容器就没用了。

DI容器应该允许使用约定来注册类型,例如将所有在“服务”中需要名称的类注册为服务。这样,您只需定义一些“规则”,无论您在应用程序中拥有多少服务,都会自动完成注册。至少这是.net中的事情,但显然手动编写50-100个类的注册是一种代码味道。

<强>更新

看起来应该是这样的

 interface ISomeService {}

 class MyService implements ISomeService { }

 class OtherService
 {
     private $svc;
     function __construct(ISomeService $svc)
     {
         $this->svc=$svc;
     }

      function doStuff()
      {
          //do stuff using  $this->svc
      }
 }

 //DiContainer
 //here you you should register things (I don't know a container for php, I'll write what I'm using in C#, but you'll get the idea)
             container.RegisterTypes(myAssembly)
            .Where(type=>type.Name.EndsWith("Service"))
            .AsSelf()
            .AsImplementedInterfaces();

上面的代码告诉容器扫描名称以“Service”(我的约定)结尾的所有类,并自动注册它们,以便在请求特定类型或由其实现的接口实现时使用类型。

在我们的示例中,这意味着当从容器请求 OtherService 的实例时,容器知道使用 MyService 类型作为的具体类型ISomeService 。容器会查看构造函数以检测对象需要的依赖项。

为了正确使用DI容器,您的(mvc)框架应该知道它,因为它不应该由您的应用程序直接使用。在某些情况下,服务定位器模式有效,但通常框架应使用容器来创建所需服务的实例

您在应用程序引导时(作为部分或与您的mvc框架集成)配置容器,就是这样。接下来,您只需定义接口和类(服务,存储库,事件处理程序等)。您应该做的唯一事情是提出一些约定,允许容器根据它们自动注册类(例如命名服务“服务”)。

DI容器首次出现在静态类型语言(java,C#)中,与使用不受类型限制的动态语言相比,使用起来更有意义(这就是我在php中使用类型提示的原因) )。它们仍然有用,但有点难以理解。