pan*_*hro 4 php design-patterns ioc-container laravel
我正在查看Laravel的服务容器文档,特别是绑定部分.
有什么区别,什么时候应该使用每种类型的绑定?文件提到:
首先,让我们看看它到底是什么:
IoC容器是一个知道如何创建实例的组件.它还知道所有潜在的依赖关系以及如何解决它们.
容器关于实例创建和依赖关系解析的知识可能由程序员指导.这就是为什么Laravel的容器为我和你提供各种绑定API的原因.
" 解决出容器 "是您经常阅读/听到的短语.这意味着您可以根据之前给她的[可选]指导告诉容器为您制作一些东西.
在继续阅读有关绑定之前,我强烈建议您阅读以下答案:
Laravel IoC Container简单易懂?
app()->bind(DatabaseWriter::class, function ($app) {
return new DatabaseWriter(
$app->make(DatabaseAdapterInterface)
);
});
Run Code Online (Sandbox Code Playgroud)
你对容器说,当你想解决一个DatabaseWriter类的实例时,遵循这个逻辑,我刚刚在闭包中告诉你,我知道的更好.每次要解决该类时,都必须遵循此并向我提供一个新实例.
您始终使用此类绑定.您正在为容器提供有关如何为您制作物品的小食谱.
与简单绑定相同,有一个明显的区别.你告诉容器我在整个应用程序中只需要一个这个类的实例.第一次解析类时,请遵循我传递给您的闭包中的逻辑,但请确保您每隔一段时间只返回一个实例来解决它.向我提供您允许的唯一实例.
这是一个单身人士吧?解析单例绑定后,将在后续调用容器时返回相同的对象实例.
显然,当您想要使用Singleton模式时,可以使用这种类型的绑定.这些日子很少见.
这就像对容器做一个忙.你没有告诉她如何实例化某个类,你自己做,只是给她实例.她为你拿着它,然后在随后的容器调用中返回它.
当你进行单元测试时,它特别方便.如果将模拟实例绑定到某个类的容器,则所有后续调用app()->make()将为您返回该模拟.所以当你使用实际的类时,你实际上是在整个应用程序中注入一个类模拟.
class QuestionsControllerTest extends TestCase
{
public function testQuestionListing()
{
$questionMock = Mockery::mock('Question')
->shouldReceive('latest')
->once()
->getMock();
// You're telling the container that everytime anyone
// wants a Question instance, give them this mock I just
// gave you.
$this->app->instance('Question', $this->questionMock);
// whatever...
}
}
Run Code Online (Sandbox Code Playgroud)
Laravel的容器为您提供了一个DSL,告诉她如何解析基元.你说当一个BillingController类想要一个$taxRate变量而它没有被传递时,给它0.2.这就像设置远处的默认值!
app()->when('App\Http\Controllers\BillingController')
->needs('$taxRate')
->give(.2);
Run Code Online (Sandbox Code Playgroud)
用例可能很少见,但偶尔也可能需要它们.这个例子可能更有感觉:
app()->when('App\Http\Controllers\CustomerController')
->needs('$customers')
->give(function() {
return Customer::paying();
});
Run Code Online (Sandbox Code Playgroud)
当您想要将接口绑定到具体实现时,可以使用它.
在阅读了有关SOLID的十几篇文章以及如何成为更好的程序员之后,您决定遵循依赖性倒置原则,而不依赖于具体实例,您依赖于抽象.
毕竟,这是一个很好的做法,在Laravel内外.
class DatabaseWriter {
protected $db;
// Any concrete implementation of this interface will do
// Now, that I depend on this DatabaseAdapterInterface contract,
// I can work with MySQL, MongoDB and WhatevaDB! Awesome!
public function __construct(DatabaseAdapterInterface $db)
{
$this->db = $db;
}
public function write()
{
$this->db->query('...');
}
}
Run Code Online (Sandbox Code Playgroud)
如果没有Laravel的容器,首先需要创建一个具体的实现DatabaseAdapterInterface并通过它DatabaseWriter的构造函数来实例化它:
$dbWriter = new DatabaseWriter(new MongodbAdapter)
Run Code Online (Sandbox Code Playgroud)
如果MongodbAdapter有自己的依赖项,您可能会在这里结束:
// Looks familiar, right?
// These are those recipes you used to give to Laravel container
// through simple binding.
$dbWriter = new DatabaseWriter(new MongodbAdapter(new MongodbConnection))
Run Code Online (Sandbox Code Playgroud)
但是在Laravel的聚会中,你告诉她当有人要求具体实施时DatabaseAdapterInterface,不要再问他们了,给他们一个MongodbAdapter:
app()->bind(DatabaseAdapterInterface::class, MongodbAdapter::class)
Run Code Online (Sandbox Code Playgroud)
然后你继续解决一个DatabaseWriter容器外的实例,就像一个老板:
$dbWriter = app()->make(DatabaseWriter::class)
Run Code Online (Sandbox Code Playgroud)
更简单,更清洁,对吧?你删除所有明显的混乱,并将其移动到其他地方.你AppServiceProvider可能.
好的,让我们看看她在这种情况下的工作方式.首先,她探究DatabaseWriter可能的依赖关系(通过反射),看到它需要一个DatabaseAdapterInterface.检查她的笔记本,回忆说你告诉她这MongodbAdapter是该界面的具体实现.制作一个并交给它DatabaseWriter.
如果你坚持依赖倒置原则,几乎所有时间都使用这些类型的绑定.
好的,足够的聊天,让我们看看她是如何工作的:https:
//github.com/laravel/framework/blob/5.3/src/Illuminate/Container/Container.php#L627
| 归档时间: |
|
| 查看次数: |
1258 次 |
| 最近记录: |