如何理解服务容器 `bind`, `make` 方法与辅助函数 `App ()` 方法?
读了文档跟几篇文章后,对服务容器的概念跟实践还是有点不清晰,所以请教一下,下面的描述也可能有基本概念认知的问题。
Laravel 中可以在服务提供者中注册一个服务容器绑定,具体可以绑定一个实例、单例,给定初始数据等,实现自动依赖注入,文档中有介绍,绑定(Binding)是在服务提供者中访问服务容器 $this->app
进行注册的,类似:
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
解析实例则通过:$this->app->make('Name')
参考这篇文章,注册好的 FileSystem 单例可以通过 app('files')
进行访问(暂时不考虑 Facade),也就是解析该单例?
问题1:两种解析方式的应用场景有区别吗?make()
需要访问 $this->app
即服务容器,而 app()
函数也返回服务容器,并且接受类或接口名称参数来解析它,所以他们的区别只是 $this->app->make()
是在服务提供者中为其他绑定注入一个解析,而 app()
方法可以在任何地方进行解析,甚至在服务提供者中也可以 app()->make()
当然这很诡异也不规范。
问题2:app()
函数的实践?app()
函数可以直接用类当参数,如 app(Foo::Class)
,自动注入依赖后返回该类的实例,所以实践是:在没有特定需求的时候,不需要注册,而是直接用 app()
自动注入依赖创建实例,或者完全是两个不同的场景?
第一个问题
如果你看看框架代码你会发现,
app()
和$this->app
是同一个东西(Ioc容器
).要用$this->app
肯定是当前类有app这个成员变量才行,而app()
是直接从容器的静态变量去取的.app()
在文档中被描述为帮助函数,目的就是在你不能$this->app
时使用.本来,这两个函数不分使用场景的,但是当你考虑测试的时候,你会发现使用$this->app
会便于写测试.举个栗子:我需要在某个类中使用容器
在测试的时候,如果我只是想mock一个容器,那么我必须想办法修改
app()
让它返回我mock的容器.但是如果我这样写:在测试时,当我要实例化这个
SomeClass
,我只需要像下面这样mock一个app传入构造函数就可以了:第二个问题
你的结论是对的,得益于
composer
的自动加载,你完全可以在框架的任何地方直接new
项目中的类.如果你没有注册,那么app(Some::class)
就是帮你new
一个对象而已.有些类在创建时,需要一些参数,这时候,你就可以注册到容器中.你在把类注册到容器时,你是在告诉容器,这个类应该怎么new
.希望能够帮到你:smile: