Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 理解IoC容器和依赖注入_Php_Oop_Inheritance_Dependency Injection_Inversion Of Control - Fatal编程技术网

Php 理解IoC容器和依赖注入

Php 理解IoC容器和依赖注入,php,oop,inheritance,dependency-injection,inversion-of-control,Php,Oop,Inheritance,Dependency Injection,Inversion Of Control,我的理解: 依赖性是指ClassA实例需要ClassB实例来实例化新的ClassA实例的情况 依赖项注入是指通过ClassA构造函数中的参数或set~DependencyNameHere~(~DependencyNameHere~$param)函数将ClassA传递给ClassB的实例。(这是我不能完全确定的领域之一) IoC容器是一个单例类(在任何给定时间只能实例化一个实例),在这里可以注册为该项目实例化这些类对象的特定方式 因此,在这一点上,我开始尝试在更复杂的场景中使用IoC容器。到目

我的理解:

  • 依赖性是指ClassA实例需要ClassB实例来实例化新的ClassA实例的情况
  • 依赖项注入是指通过ClassA构造函数中的参数或set~DependencyNameHere~(~DependencyNameHere~$param)函数将ClassA传递给ClassB的实例。(这是我不能完全确定的领域之一)
  • IoC容器是一个单例类(在任何给定时间只能实例化一个实例),在这里可以注册为该项目实例化这些类对象的特定方式
因此,在这一点上,我开始尝试在更复杂的场景中使用IoC容器。到目前为止,似乎为了使用IoC容器,我只限于一个has-a关系,对于我想要创建的任何类,它都要在IoC容器中定义依赖项。如果我想创建一个继承类的类,但前提是父类是以特定的方式创建的,它是在IoC容器中注册的,该怎么办

例如:我想创建mysqli的一个子类,但我想在IoC容器中注册这个类,以便只实例化以我以前在IoC容器中注册的方式构造的父类。我想不出一种不复制代码就可以做到这一点的方法(因为这是一个学习项目,所以我试图让它尽可能“纯粹”)

下面是我的一些问题:

  • 我试图在不违反OOP原则的情况下完成上述工作是否可行?我知道C++中可以使用动态内存和复制构造函数来完成它,但是我在PHP中还没有找到那种功能。(我承认,除了_构造之外,我几乎没有使用任何其他神奇方法的经验,但是从阅读和_克隆中,如果我理解正确,我无法在构造函数中使用它使正在实例化的子类成为父类实例的克隆)
  • 与IoC相关的所有依赖类定义应该放在哪里?(我的IoC.php是否应该在顶部有一大堆require_once('dependencyClassDefinition.php')?我的直觉反应是有更好的方法,但我还没有想出一个)
  • 我应该在哪个文件中注册我的对象?当前正在执行类定义之后对IoC.php文件中的IoC::register()的所有调用
  • 在注册需要依赖关系的类之前,我是否需要在IoC中注册依赖关系?因为在我实际实例化IoC中注册的对象之前,我不会调用匿名函数,所以我猜不会,但这仍然是一个问题
  • 还有什么我忽略了的,我应该做或使用的吗?我试图一步一个脚印地完成它,但我也不想知道我的代码是可重用的,最重要的是,对我的项目一无所知的人可以阅读和理解它
简单地说(因为这不是一个仅限于OOP世界的问题),依赖关系是组件a需要(依赖)组件B来完成它应该做的事情的情况。该词还用于描述此场景中的依赖组件。在OOP/PHP术语中,考虑下面的例子,即强制性的汽车类比:

class Car {

    public function start() {
        $engine = new Engine();
        $engine->vroom();
    }

}
汽车
取决于
发动机
<代码>发动机是
汽车
的依赖项。但这段代码相当糟糕,因为:

  • 依赖是隐性的;直到你检查
    汽车的代码,你才知道它在那里
  • 类是紧密耦合的;出于测试目的,您不能将
    发动机
    替换为
    模拟发动机
    ,或在不修改
    汽车
    的情况下扩展原发动机的
    涡轮发动机
  • 对于一辆汽车来说,为自己制造发动机看起来有点傻,不是吗
依赖注入是解决所有这些问题的一种方法,它使
汽车
需要
引擎
这一事实明确并明确地为其提供一个:

class Car {

    protected $engine;

    public function __construct(Engine $engine) {
        $this->engine = $engine;
    }

    public function start() {
        $this->engine->vroom();
    }

}

$engine = new SuperDuperTurboEnginePlus(); // a subclass of Engine
$car = new Car($engine);
上面是构造函数注入的一个示例,其中依赖项(依赖对象)通过类构造函数提供给依赖项(使用者)。另一种方法是在
Car
类中公开
setEngine
方法,并使用它注入
Engine
的实例。这被称为setter注入,主要用于应该在运行时交换的依赖项

任何一个非平凡的项目都是由一堆相互依赖的组件组成的,它很容易忘记什么东西很快就被注入到哪里。依赖项注入容器是一个对象,它知道如何实例化和配置其他对象,知道它们与项目中其他对象的关系,并为您执行依赖项注入。这使您可以集中管理所有项目的(相互)依赖关系,更重要的是,可以更改/模拟其中的一个或多个,而无需编辑代码中的大量位置

让我们抛开汽车的类比,看看OP试图实现什么作为一个例子。假设我们有一个
数据库
对象,具体取决于
mysqli
对象。假设我们想要使用一个真正原始的依赖索引容器类
DIC
,它公开了两个方法:
register($name,$callback)
注册一种在给定名称下创建对象的方法,以及
resolve($name)
从该名称获取对象。我们的容器设置如下所示:

$dic = new DIC();
$dic->register('mysqli', function() {
    return new mysqli('somehost','username','password');
});
$dic->register('database', function() use($dic) {
    return new Database($dic->resolve('mysqli'));
});
请注意,我们告诉容器从自身获取
mysqli
的一个实例来组装ins
$database = $dic->resolve('database');