【问题标题】:ZF2: Dependency injection done the proper wayZF2:依赖注入以正确的方式完成
【发布时间】:2014-11-25 04:23:35
【问题描述】:

我是 ZendFramework 2 和整个 DI 理念的新手。

这是我需要实现的目标:

  1. 创建多个扩展单个 AbstractModel 的模型类
  2. 使用带有依赖项的 DI 提供 AbstractModel(在我的例子中是学说实体管理器)
  3. 在我需要的地方使用祖先类作为普通类

为了更好地解释 3. 让我们看看这个例子:

class Ancestor extends Parent { }

在控制器中,或者理想的任何地方:

$ancestor = new Ancestor();
$ancestor->doStuffWithEntityManager();

在初始化祖先时,它必须已经知道注入的资源。

这甚至可能吗?如果不使用它的默认形式,我可以通过一些服务管理器等初始化祖先,只要我不需要指定每个祖先。我需要告诉 zend:将这个和那个注入到每个扩展/实现 X 的类中。

有什么想法吗?

P.S.:正如我所说,我是新手,所以请指定配置/类文件,我必须添加每段示例代码。

【问题讨论】:

    标签: php class zend-framework dependency-injection zend-framework2


    【解决方案1】:

    在我的架构中,我这样做如下。首先:我创建一个服务:

    class Module 
    {
        public function getServiceConfig()
        {
            return array(
                'factories' => array(
                    'my-service-name'   => 'MyNamespace\Factory\MyServiceFactory'
                )
            );
        }
    }
    

    然后我创建 ServiceFactory。这将是处理所有依赖项的地方。

    <?php
    namespace MyNamespace\Factory;
    
    use Zend\ServiceManager\ServiceLocatorInterface;
    use Zend\ServiceManager\FactoryInterface;
    use MyNamespace\Service\SomeService;
    
    class MyServiceFactory implements FactoryInterface
    {
        /**
         * Create service
         *
         * @param ServiceLocatorInterface $serviceLocator
         * @return \MyNamespace\Service\SomeService
         */
        public function createService(ServiceLocatorInterface $serviceLocator)
        {
            $service = new SomeService();
            $service->setEntityManager($serviceLocator->get('Doctrine\ORM\EntityManager'));
            return $service;
        }
    }
    

    MyService-Class 甚至可以有更多的依赖,在我的例子中,由于它们实现的接口,它们会自动注入。你可以看到一个例子right here。然后,特定的 EntityService 只需要一个定义存储库的函数,例如 this example here

    您也可能会被建议阅读Rob Allens introduction to ServiceManager Configuration Keys。具体阅读“初始化程序”部分,我想这是您主要关心的问题?

    我希望这涵盖了您的问题。

    【讨论】:

    • 相当。我的实现(目前有效)是相似的。我注册了一个数据库服务并在其中定义了一个get($class) 方法。然后我用我需要的模型类在控制器中调用服务的 get 方法。服务工厂创建一个实例并注入我指定的依赖项。我不确定这是正确的 DI,但我想它就足够了。
    • @Sam 对于循环依赖的情况,您有什么解决方案吗?例如,在您的回答中,如果Doctrine\ORM\EntityManager 需要SomeService 的实例怎么办?会有一个永无止境的递归循环。
    • @binnyb 这听起来像是糟糕的设计:) 除了将依赖关系重构为有意义的东西之外,没有真正的解决方案。可能需要适当的示例来帮助您。
    【解决方案2】:

    您可以注入创建自定义存储库类的实体管理器,并将其注入覆盖 find* 方法调用

    Using EntityManager inside Doctrine 2.0 entities

    但是我建议您检查您的设计,因为它不是从实体对数据库的正常调用

    【讨论】:

      【解决方案3】:
      class Parent {
          private $em;
      
          public function __construct(\Doctrine\ORM\EntityManager $em) {
              $this->em = $em;
          }
      }
      
      class Ancestor extends Parent { }
      
      // To use, create an EntityManager $em
      
      $ancestor = new Ancestor($em);
      $ancestor->doStuffWithEntityManager(); // Uses $this->em internally
      

      这就是依赖注入的全部内容。另见http://fabien.potencier.org/article/11/what-is-dependency-injection

      查看此处获取/创建 ZF2 中的 EntityManager:http://samminds.com/2012/07/a-blog-application-part-1-working-with-doctrine-2-in-zend-framework-2/

      基本上,在从AbstractActionController 扩展的控制器中,您可以这样做:

      $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
      

      【讨论】:

      • 如果文档在现实世界中是可以理解或适用的,我就不会在这里问了。 create an EntityManager $em somehow 正是我不知道该怎么做。
      • 好的,希望我已经澄清了。
      • 不,因为您的代码实际上不是 DI。它只是创建一个对象并将实体管理器作为参数传递给构造函数。除了我熟悉 DI 的概念外,我不知道如何让 zf2 使用它的配置为我完成所有繁重的工作。
      • 上面的代码就是 DI。 “它只是创建一个对象并将实体管理器作为参数传递给构造函数”。这称为构造函数注入,是执行 DI 的两种方法之一。
      • 仍然与我的问题无关。
      猜你喜欢
      • 1970-01-01
      • 2016-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多