首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PHP依赖注入

PHP依赖注入
EN

Stack Overflow用户
提问于 2012-04-09 01:50:46
回答 4查看 10.2K关注 0票数 10

我正在试着理解依赖注入,并且在很大程度上我理解它。

但是,假设由于某种原因,我的一个类依赖于几个类,而不是在构造函数中将所有这些类都传递给这个类,有没有更好、更合理的方法?

我听说过DI容器,这是我解决这个问题的方式吗?我应该从哪里开始这个解决方案?是否将依赖项传递给DIC,然后将其传递给需要这些依赖项的类?

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-04-09 01:59:51

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

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

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

代码语言:javascript
复制
// 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容器作为参数:

代码语言:javascript
复制
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容器创建为类本身,并使用单独注入其中的组件类来实例化它,而不是像我上面所做的那样创建数组(这很简单)。使用对象而不是数组的一个好处是,默认情况下,它将通过引用传递到使用它的类中,而数组是通过值传递的(尽管数组中的对象仍然是引用)。

编辑

在某些方面,对象比数组更灵活,尽管在最初的代码中更加复杂。

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

代码语言:javascript
复制
Class DIContainer {
  public $config;
  public $db;
  public $client;

  // The DI container can build its own member objects
  public function __construct($params....) {
    $this->config = new Config();

    // These vars might be passed in the constructor, or could be constants, or something else
    $this->db = new DB($user, $pass, $db, $whatever);

    // Same here -  the var may come from the constructor, $_SESSION, or somewhere else
    $this->client = new ClientInfo($clientid);
  }
}
票数 12
EN

Stack Overflow用户

发布于 2012-04-09 04:44:45

依赖注入!== DIC

人们真的不应该再迷惑他们了。Dependency Injection是来自Dependency Inversion principle的想法。

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

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

在这种情况下,依赖注入容器将只隐藏底层设计问题。

如果你想了解更多关于依赖注入的知识,我建议你看看youtube上的"Clean Code Talks“:

  • The Clean Code Talks - Don't Look For Things!
  • The Clean Code Talks - "Global State and Singletons"
票数 31
EN

Stack Overflow用户

发布于 2016-08-05 16:08:04

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

代码语言:javascript
复制
namespace Gica\Interfaces\Dependency;

interface AbstractFactory
{
    public function createObject($objectClass, $constructorArguments = []);
}

抽象的工厂实现是:

代码语言:javascript
复制
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\依赖项;

代码语言:javascript
复制
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
    }
}

dependency container是标准的。客户端代码可能如下所示:

代码语言:javascript
复制
$abstractFactory = $container->get(\Gica\Interfaces\Dependency\AbstractFactory::class);

$someHelper = $abstractFactory->createObject(\Web\Helper\SomeHelper::class);

echo $someHelper->helpAction();

请注意,依赖关系是隐藏的,我们可以专注于主要业务。我的客户机代码不关心也不知道$someHelper需要Authenticator,或者helpAction需要SomeObject来完成它的工作;

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10064970

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档