PHP依赖注入

PHP依赖注入,php,dependency-injection,Php,Dependency Injection,我正试着了解依赖注入,我大部分都理解它 但是,如果出于某种原因,我的一个类依赖于几个类,而不是将所有这些传递给构造函数中的这个类,那么有更好、更合理的方法吗 我听说过DI容器,这就是我解决这个问题的方法吗?从何处开始使用此解决方案?我是否将依赖项传递给我的DIC,然后将其传递给需要这些依赖项的类 任何能为我指明正确方向的帮助都是非常好的。如果您有几个依赖项需要处理,那么DI容器就是解决方案 DI容器可以是由所需的各种依赖对象构成的对象或数组,这些依赖对象被传递给构造函数并解包 假设您需要一个配置

我正试着了解依赖注入,我大部分都理解它

但是,如果出于某种原因,我的一个类依赖于几个类,而不是将所有这些传递给构造函数中的这个类,那么有更好、更合理的方法吗

我听说过DI容器,这就是我解决这个问题的方法吗?从何处开始使用此解决方案?我是否将依赖项传递给我的DIC,然后将其传递给需要这些依赖项的类


任何能为我指明正确方向的帮助都是非常好的。

如果您有几个依赖项需要处理,那么DI容器就是解决方案

DI容器可以是由所需的各种依赖对象构成的对象或数组,这些依赖对象被传递给构造函数并解包

假设您需要一个配置对象、一个数据库连接和一个传递给每个类的客户机信息对象。您可以创建一个包含它们的数组:

// Assume each is created or accessed as a singleton, however needed...
// This may be created globally at the top of your script, and passed into each newly
// instantiated class
$di_container = array(
  'config' = new Config(),
  'db' = new DB($user, $pass, $db, $whatever),
  'client' = new ClientInfo($clientid)
);
类构造函数接受DI容器作为参数:

class SomeClass {
  private $config;
  private $db;
  private $client;
 
  public function __construct(&$di_container) {
    $this->config = $di_container['config'];
    $this->db = $di_container['db'];
    $this->client = $di_container['client'];
  }
}
您也可以将DI容器创建为类本身,并使用单独注入的组件类对其进行实例化,而不是像我上面所做的那样创建数组(这很简单)。使用对象而不是数组的一个好处是,默认情况下,它将通过引用传递到使用它的类中,而数组是通过值传递的(尽管数组中的对象仍然是引用)

编辑 在某些方面,对象比数组更灵活,尽管最初编写代码更复杂

容器对象还可以在其构造函数中创建/实例化包含的类(而不是在外部创建并传入它们)。这可以为使用它的每个脚本节省一些代码,因为您只需要实例化一个对象(它本身实例化了其他几个对象)


我建议您使用Singltone或Mutlitone。在这些情况下,您将始终能够通过静态类的方法获取对象

另一种方法(找不到正确的模式名,但可能是
Registry
)是使用一个全局静态对象来存储多个对象的实例。例如(简化代码,无任何检查):

依赖注入!==DIC 人们真的应该停止混淆它们。这是我的想法

DIC是“魔术疗法”,它承诺让您使用依赖注入,但在PHP中,通常是通过打破面向对象编程的所有其他原则来实现的。最糟糕的实现往往也会通过静态
注册表
单例
将其全部附加到全局状态

无论如何,如果您的类依赖于太多的其他类,那么一般来说,这意味着类本身存在设计缺陷。你基本上有一个类有太多的原因需要改变,因此,打破了

在这种情况下,依赖项注入容器将只隐藏基线设计问题

如果您想了解更多关于依赖注入的信息,我建议您观看youtube上的“干净代码对话”:

    • 我已经写了一篇关于这个问题的文章。 ideea将结合使用抽象工厂和依赖项注入来实现(可能的嵌套)依赖项的透明依赖项解析。我将在此处复制/粘贴主要代码片段:

      namespace Gica\Interfaces\Dependency;
      
      interface AbstractFactory
      {
          public function createObject($objectClass, $constructorArguments = []);
      }
      
      抽象工厂实现是:

      namespace Gica\Dependency;
      
      class AbstractFactory implements \Gica\Interfaces\Dependency\AbstractFactory, \Gica\Interfaces\Dependency\WithDependencyInjector
      {
          use WithDependencyInjector;
      
          /**
           * @param string $objectClass
           * @param array $constructorArguments
           * @return object instanceof $class
           */
          public function createObject($objectClass, $constructorArguments =     [])
          {
              $instance = new $objectClass(...$constructorArguments);
      
              $this->getDependencyInjector()->resolveDependencies($instance);
      
              return $instance;
          }
      }
      
      依赖关系注入器如下所示: 名称空间Gica \依赖关系

      class DependencyInjector implements \Gica\Interfaces\Dependency\DependencyInjector
      {
          use \Gica\Traits\WithDependencyContainer;
      
          public function resolveDependencies($instance)
          {
              $sm = $this->getDependencyInjectionContainer();
      
              if ($instance instanceof \Gica\Interfaces\WithAuthenticator) {
                  $instance->setAuthenticator($sm->get(\Gica\Interfaces\Authentication\Authenticator::class));
              }
              if ($instance instanceof \Gica\Interfaces\WithPdo) {
                  $instance->setPdo($sm->get(\Gica\SqlQuery\Connection::class));
              }
      
              if ($instance instanceof \Gica\Interfaces\Dependency\WithAbstractFactory) {
                  $instance->setAbstractFactory($sm->get(\Gica\Interfaces\Dependency\AbstractFactory::class));
              }
              //... all the dependency declaring interfaces go below
          }
      }
      
      这是标准的。 客户端代码可能如下所示:

      $abstractFactory = $container->get(\Gica\Interfaces\Dependency\AbstractFactory::class);
      
      $someHelper = $abstractFactory->createObject(\Web\Helper\SomeHelper::class);
      
      echo $someHelper->helpAction();
      
      请注意,依赖关系是隐藏的,我们可以关注主要业务。我的客户端代码不关心或不知道$someHelper需要一个
      验证器
      ,或者helpAction需要一个
      SomeObject
      来完成它的工作

      在后台会发生很多事情,检测、解析和注入很多依赖项。 请注意,我没有使用
      new
      操作符来创建
      $someObject
      。实际创建对象的责任被传递给
      AbstractFactory


      p.S.Gica是我的昵称:)

      “依赖注入”是一个25美元的术语,用于表示5美分的概念
      ——我考虑过单例,但是,我读到DI是前进的方向。DI是一个很好的解决方案,但在我看来,它在Java中有更好的实现(即),不是用PHPitself@RepWhoringPeeHaa解释一下你的观点,我想我已经解释过了。全局变量是不好的,而代码中的全局变量是花哨的。我建议你看teresko回答中的视频。@Azirius我在上面添加了一个例子,对象更灵活。这是一个相当可怕的DIC实现。另外,当您不向数组写入时,将数组作为引用传递有什么意义?您真的会向构造函数中的引用数组写入吗?!那太疯狂了。或者只是因为你不懂php5中的“写在纸上拷贝”的意思……不,你不应该。特别是不像柴油机那么可怕的东西。这是服务定位器反模式。依赖注入是实现Ioc的一种方法,对吗?
      class DependencyInjector implements \Gica\Interfaces\Dependency\DependencyInjector
      {
          use \Gica\Traits\WithDependencyContainer;
      
          public function resolveDependencies($instance)
          {
              $sm = $this->getDependencyInjectionContainer();
      
              if ($instance instanceof \Gica\Interfaces\WithAuthenticator) {
                  $instance->setAuthenticator($sm->get(\Gica\Interfaces\Authentication\Authenticator::class));
              }
              if ($instance instanceof \Gica\Interfaces\WithPdo) {
                  $instance->setPdo($sm->get(\Gica\SqlQuery\Connection::class));
              }
      
              if ($instance instanceof \Gica\Interfaces\Dependency\WithAbstractFactory) {
                  $instance->setAbstractFactory($sm->get(\Gica\Interfaces\Dependency\AbstractFactory::class));
              }
              //... all the dependency declaring interfaces go below
          }
      }
      
      $abstractFactory = $container->get(\Gica\Interfaces\Dependency\AbstractFactory::class);
      
      $someHelper = $abstractFactory->createObject(\Web\Helper\SomeHelper::class);
      
      echo $someHelper->helpAction();