gpt4 book ai didi

php - 什么是依赖注入(inject)容器?

转载 作者:可可西里 更新时间:2023-11-01 13:52:28 26 4
gpt4 key购买 nike

我试图理解依赖注入(inject)容器的作用,因为它让我觉得它是可维护代码的基础。

据我了解,DIC 就像标题所暗示的那样:一个容器,其中所有依赖项都收集在一起。不是在整个应用程序中看到 new Foo\Bar,而是在容器内部生成所有新实例,然后在需要它们的地方相互传递(例如,Model 使用 Database 实例化,它是使用 Config 的实例实例化)。

我试图制作一个非常简单的 DIC。这是结果。

在我的前端 Controller 中,我正在实例化一个新的 App\Core\Container

我的 Container 看起来像这样:

<?php

namespace App\Core;

use App\Config;

class Container
{
public $config;
public $router;
public $database;

public $model;
public $view;
public $controller;

public function __construct()
{
$this->config = new Config;
$this->router = new Router;
$this->database = new Database($this->config);
}

public function add()
{
// add dependencies from the outside?
}

public function getInstance(/* string */)
{
// return an instance for use somewhere?
}

public function newModel($model)
{
$model = $this->getModelNamespace() . $model;
$this->model = new $model($this->database);
return $this->model;
}

private function getModelNamespace()
{
$namespace = 'App\Models\\';
if (array_key_exists('namespace', $this->params = [])) {
$namespace .= $this->params['namespace'] . '\\';
}
return $namespace;
}

public function newView($params)
{
$this->view = new View($this->model, $params);
return $this->view;
}

public function newController($controller)
{
$controller = $this->getControllerNamespace() . $controller;
$this->controller = new $controller;
return $this->controller;
}

private function getControllerNamespace()
{
$namespace = 'App\Controllers\\';
if (array_key_exists('namespace', $this->params = [])) {
$namespace .= $this->params['namespace'] . '\\';
}
return $namespace;
}
}

问题
  • 我上面的实现虽然很简单,但可以归类为基本的依赖注入(inject)器吗?
  • 依赖注入(inject)容器通常由一个类组成吗?
  • 最佳答案

    Note: the first three headings answer your questions, while the following ones answer anticipated questions and provide coverage of anything in the first two sections.


    这可以归类为依赖注入(inject)容器吗?
    不,这看起来不像依赖注入(inject)容器。依赖注入(inject)容器是为了 通过确定、创建和注入(inject)所有依赖项来减少实例化所需的工作。 相反,您拥有的似乎是工厂和服务定位器的组合。
    工厂抽象对象的创建。这基本上就是你的 Container课在做。通过调用指定的方法(即 newModel),您的容器负责定位要实例化的确切对象并构造该对象的实例。
    我将其称为“糟糕”工厂的原因是它开始看起来可能用于定位服务。 服务定位器 通过隐藏对象的依赖来工作:而不是依赖于 GenericService ,对象可能依赖于服务定位器。给定服务定位器,它可以请求 GenericService 的实例。 .我看到类似的行为开始在您的 add() 中占据一席之地。和 getInstance()方法。服务定位器通常被认为是反模式,因为它们抽象了依赖关系,因此使代码无法测试!
    依赖注入(inject)容器是否由一个类组成?
    这取决于。你可以很容易地用一个类制作一个简单的依赖注入(inject)容器。问题在于,简单容器的性质往往会变得更先进,成为不那么简单的容器。当您开始改进您的模式时,您需要考虑不同的组件如何协同工作。问问自己:他们是否遵循 SOLID 原则?如果没有,则需要重构。
    什么是依赖注入(inject)容器?
    我在上面说过,但再说一遍:依赖注入(inject)容器旨在通过确定、创建和注入(inject)所有依赖项来减少实例化所需的工作。 DIC 将查看一个类的所有依赖项,以及这些依赖项可能具有的所有依赖项,依此类推...从这个意义上说,容器负责 分层实例化所有依赖项 . Container您提供的类依赖于预定义类的非常严格的定义。例如,模型层中的类似乎只依赖于数据库连接。 (可以对 Controller 和 View 层中的类进行类似的陈述)。
    依赖注入(inject)容器如何查找依赖?
    依赖注入(inject)容器将检测依赖关系。通常,这通过 3 种机制中的一种发生: Autowiring 、注释和定义。 PHP-DI 文档很好地说明了这三者的含义 here .简而言之: Autowiring 通过 reflecting 检测依赖关系在类上,注解用于使用类上方的注释写入依赖项,定义用于硬编码依赖项。就个人而言,我更喜欢 Autowiring ,因为它干净且简单。
    我可以创建一个简单的依赖注入(inject)容器吗?
    是的你可以。从注入(inject)器应该能够实例化任何对象(服务、 View 、 Controller 等)的想法开始。它需要查看相关对象并分层实例化所有依赖项(提示:可能通过某种递归方法)。
    使用 Autowiring 的简单注入(inject)器的快速示例如下所示:
    <?php
    class Injector
    {
    public function make($className)
    {
    $dependencies = [];

    //Create reflection of the class-to-make's constructor to get dependencies
    $classReflection = new ReflectionMethod($className, "__construct");

    foreach($classReflection->getParameters() as $parameter) {
    $dependencyName = $parameter->getClass()->getName();

    //Use the injector to make an instance of the dependency
    $dependencies[] = $this->make($dependencyName);
    }

    $class = new ReflectionClass($className);

    //Instantiate the class with all dependencies
    return $class->newInstanceArgs($dependencies);
    }
    }
    使用类似以下内容进行测试,您可以看到注入(inject)器如何递归检查和实例化所有依赖项
    class A {
    protected $b;
    public function __construct(B $b) { $this->b = $b; }
    public function output(){ $this->b->foo(); }
    }

    class B {
    protected $c;
    public function __construct(C $c) { $this->c = $c; }
    public function foo() { $this->c->bar(); }
    }

    class C {
    public function __construct() { }
    public function bar() { echo "World!"; }
    }

    $injector = new Injector;

    $a = $injector->make("A");
    //No need to manually instantiate A's dependency, B, or B's dependency, C

    $a->output();
    这个基本的喷油器有明显的故障。例如,如果两个类相互依赖(应该进行检查),则有可能造成递归灾难。但是,按原样,这可以作为注入(inject)器外观的基本示例。
    注入(inject)器与依赖注入(inject)容器
    为了使其更强大并符合“依赖注入(inject)容器”的定义,您需要一种跨多个共享实例化实例的方法 make()调用。例如,您可能有另一个名为 share() 的方法。 .此方法将存储传递给它的实例。每当一个类通过 make() 构建时方法并依赖于先前共享的类,而不是实例化一个新实例,它会使用已经实例化的实例。
    对于一个简单而强大的依赖注入(inject)容器,我建议 Auryn ,但无论如何,在使用现有的之前,请尝试了解并创建自己的。

    关于php - 什么是依赖注入(inject)容器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38702676/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com