gpt4 book ai didi

laravel - 简单来说什么是 Laravel IoC Container?

转载 作者:行者123 更新时间:2023-12-02 06:05:07 25 4
gpt4 key购买 nike

任何人都可以用简单易懂的语言解释依赖注入(inject)和 IoC 容器,因为我是 laravel 的初学者。谢谢

最佳答案

答案变得比我最初希望的要长。我包括了一些背景信息。如果您正在寻找短期解释,请阅读 IoC-Container 的第一段和粗体段落。
依赖注入(inject)
依赖注入(inject)是一种设计模式,顾名思义。它将对象注入(inject)到其他对象的构造函数或方法中,以便一个对象依赖于一个或多个其他对象 .

<?php

class DatabaseWriter {

protected $db;

public function __construct(DatabaseAdapter $db)
{
$this->db = $db;
}

public function write()
{
$this->db->query('...');
}

}
您可以看到我们需要类构造函数 a DatabaseAdapter要传递的实例。由于我们在构造函数中这样做,没有它就不能实例化该类的对象: 我们正在注入(inject)一个依赖项 .现在,我们知道 DatabaseAdapter始终存在于我们可以轻松依赖的类中。 write()方法只是调用适配器上的方法,因为我们肯定知道它存在,因为我们使用了 DI。
使用 DI 而不是误用静态类、上帝对象和其他类似的东西的巨大优势就是 您可以轻松追踪依赖项的来源 .
另一个巨大的优势是, 您可以轻松地交换依赖项 .如果您想使用依赖项的另一个实现,只需将其传递给构造函数。您不再需要寻找硬编码实例来交换它们。
撇开这样一个事实,通过使用依赖注入(inject),您可以轻松地对您的类进行单元测试,因为您可以只模拟依赖项,而硬编码依赖项几乎不可能实现。
依赖注入(inject)的三种类型
构造函数注入(inject)
上面解释的依赖注入(inject)的类型叫做 构造函数注入(inject) .这只是意味着依赖项作为参数传递给类构造函数。然后将依赖项存储为属性,从而在类的所有方法中可用。这里的一大优点是,如果不传递依赖项,类的对象就不能存在。
二传手注入(inject)
这种类型使用专用方法来注入(inject)依赖项。而不是使用构造函数。使用 Setter 注入(inject)的优点是,您可以向对象添加依赖项 创建之后 .常用于 可选依赖项 . Setter 注入(inject)也可以很好地整理您的构造函数,并且仅在您需要它们的方法中拥有您的依赖项。
<?php

class RegisterUserService {

protected $logger;

public function setLogger( Logger $logger )
{
$this->logger = $logger;
}

public function registerUser()
{
// Do stuff to register the user
if($this->logger)
$this->logger->log("User has been registered");
}

}

$service = new RegisterUserService;
$service->registerUser(); // Nothing is Logged

$service->setLogger(new ConcreteLogger);
$service->registerUser(); // Now we log
可以在没有任何依赖关系的情况下实例化对象。有一种方法可以注入(inject)可以选择性调用的依赖项( setLogger() )。现在取决于方法实现是否使用依赖项(如果未设置)。
值得指出的是,使用 Setter 注入(inject)要谨慎。在尚未注入(inject)的依赖项上调用方法或访问属性将导致令人讨厌的 Fatal error: Call to a member function XXX() on a non-object .因此,每次访问依赖项时,都必须先对其进行空检查。一个更简洁的方法是使用 Null Object Pattern并将依赖项移动到构造函数中(作为可选参数,如果没有传递任何内容,则在类中创建空对象)
接口(interface)注入(inject)
接口(interface)注入(inject)的基本思想是,在接口(interface)中定义注入(inject)依赖项的方法。需要依赖的类必须实现接口(interface)。从而确保所需的依赖可以正确地注入(inject)到依赖对象中。它是之前解释过的 Setter 注入(inject)的一种更严格的形式。
<?php

interface Database {

public function query();

}

interface InjectDatabaseAccess {

// The user of this interface MUST provide
// a concrete of Database through this method
public function injectDatabase( Database $db );

}

class MySQL implements Database {

public function query($args)
{
// Execute Query
}

}

class DbDoer implements InjectDatabaseAccess {

protected $db;

public function injectDatabase( Database $db )
{
$this->db = $db;
}

public function doSomethingInDb($args)
{
$this->db->query();
}

}

$user = new DbDoer();
$user->injectDatabase( new MySQL );
$user->doSomethingInDb($stuff);
接口(interface)注入(inject)的意义是有争议的。我个人从未使用过它。我更喜欢构造函数注入(inject)而不是它。这使我能够完成完全相同的任务,而无需注入(inject)器端的额外接口(interface)。
依赖倒置
除了依赖于具体的实例,我们还可以依赖于抽象。
<?php

class DatabaseWriter {

protected $db;

public function __construct(DatabaseAdapterInterface $db)
{
$this->db = $db;
}

public function write()
{
$this->db->query('...');
}

}
现在我们 inverted the control .我们现在可以注入(inject)消耗 type hinted 的任何实例,而不是依赖具体实例。界面。接口(interface)负责后面的具体实例实现我们将要使用的所有方法,以便我们仍然可以在依赖类中依赖它们。
确保你得到那个,因为它是 IoC-Container 的核心概念。
IoC 容器
用我能想到的最短术语来说,我会这样描述 IoC 容器:

The IoC-Container is a component that knows how instances are created and knows of all their underlying dependencies and how to resolve them.


如果我们以上面的例子为例,想象一下 DatabaseAdapter本身有它自己的依赖关系。
class ConcreteDatabaseAdapter implements DatabaseAdapterInterface{

protected $driver;

public function __construct(DatabaseDriverInterface $driver)
{
$this->driver = $driver;
}

}
所以为了能够使用 DatabaseAdapter您需要传入 DatabaseDriverInterface 的实例抽象作为依赖。
但是你的DatabaseWriter class 不知道,也不应该知道 . DatabaseWriter应该不在乎怎么了 DatabaseAdapter工作,它应该只关心一个 DatabaseAdapter被传递而不是它需要如何创建。这就是 IoC-Container 派上用场的地方。
App::bind('DatabaseWriter', function(){
return new DatabaseWriter(
new ConcreteDatabaseAdapter(new ConcreteDatabaseDriver)
);
});
正如我已经说过的, DatabaseWriter本身对它的依赖项的依赖项一无所知。但是 IoC-Container 知道它们的所有信息,也知道在哪里可以找到它们。所以最终当 DatabaseWriter类将被实例化,首先询问 IoC-Container 需要如何实例化 .这就是 IoC-Container 所做的。
简单地说(如果您喜欢设计模式)。它有点像 的组合依赖注入(inject)容器 (我已经在上面解释过)和 Service Locator .

关于laravel - 简单来说什么是 Laravel IoC Container?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24484782/

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