时间:2021-07-01 10:21:17 帮助过:4人阅读
IOC
和 DI
概念的我, 勉强只能看懂 register
方法在做什么能不能举个例子? 文档好像很不详细
对于刚理解 IOC
和 DI
概念的我, 勉强只能看懂 register
方法在做什么
有人帮忙解释下吗
如果你对 IoC 和 DI 还有点模糊,可以参考如下链接,建议按照如下顺序进行阅读:
1.Laravel 官方文档中对 Service Container 和 Service Provider 的描述,按照目前的积累的经验进行初步理解
2.一个形象的 IoC 概述
3.通过简单的 PHP 代码描述 IoC
4.IoC 的用途、分类的详细叙述
最后再回过头来再参考一下 Service Container 和 Service Provider 文档,并且查看用户请求的生命周期概述:Request Lifecycle,基本上都可以非常清晰的理解。
现在有了 IoC 和 Laravel 请求生命周期的基础,了解 ServiceProvider 就不会太难。
继承自 ServiceProvider 的类中一般重写两个重要的函数:register 和 boot 方法。
有一天我突然想用 Laravel 实现一个程序,通过输入问题来获取 SegmentFault 上的答案列表链接,废话少说上代码:
class SegmentFault {
private $server;
public function __construct($server)
{
$this->server = $server;
}
/**
* Retrieve the answers
*/
public function answer($question)
{
return $this->server . $question;
}
}
回到 Controller,现在来调用 SegmentFault 这个类。你需要手动去实例化他吗?不,Laravel 会自动帮你实例化:
public function index(SegmentFault $segmentFault) {
return $segmentFault->answer('What is Service Provider in Laravel ?');
}
看来我宝刀未老,加上优美的 Laravel 框架分分钟搞定,激动的我赶紧刷新一下页面:
臣卜木曹,报错了,看错误提示明显是没办法解析 SegmentFault 的参数,说好的自动依赖注入呢!?
不对,我需要传入 SegmentFault 的搜索链接参数(不然 Laravel 怎么会知道需要构造什么参数呢),但是这样子要手动实例化。。不就传个参数吗,我传:
public function index() {
$segmentFault = new SegmentFault('https://segmentfault.com/search?q=');
return $segmentFault->answer('What is Service Provider in Laravel ?');
}
这回没问题了。
现在我想在其他页面也提供这个功能,似乎每次都要去实例化有点麻烦啊。假如有一天 SegmentFault 换了域名,就要修改十几个函数......
想想这严重的结果,不得不改进这个程序。好,回头来看 IoC。既然 SegmentFault 这个类实例化时需要传入参数,搜搜文档,原来还挺简单的,先建个 ServiceProvider 调教一下:
class SegmentFaultServiceProvider extends ServiceProvider {
public function register() {
$this->app->bind(SegmentFault::class, function() {
return new SegmentFault('https://segmentfault.com/search?q=');
});
}
}
这样子一来就把依赖信息配置好了,Laravel 知道怎么正确实例化这个类了,赶紧改写程序:
public function index(SegmentFault $segmentFault) {
return $segmentFault->answer('What is Service Provider in Laravel ?');
}
咦,刷新网页还是报错了!? 哦对了,还需要在 config/app.php 中注册这个 Provider:
'providers' => [
// ...
App\Providers\SegmentFaultServiceProvider::class,
]
再刷新,现在可以正常工作了,So cool !! 我不禁从椅子上跳起来。
IoC 是将内部设计的类交给系统去控制,但是有些类在初始化的时候,需要制定特定的参数,或者当你需要将实现类绑定到某个接口,这时候就必须对这些依赖进行配置,系统才能正确解析并引用。
而 register 就是这样一个地方,你可以在 register 配置类的依赖,绑定实现类到接口,设置类的别名等等。
而 boot 方法在 register 方法之后调用,这就意味着,你无须担心在注入某个实例的时候,他还没有被绑定或实例化。
例如你建立了 SegmentFault 和 SegmentFaultApi 两个类,前者依赖与后者,但是在 register 中你不确定那个类先被实例化了,那么你可以在 boot 中再对后者进行引用,因为此时两个类都已经进行正确的配置。
providers 方法用于延迟加载的 ServiceProvider,比如希望在引用的时候再让系统去解析那个类,那么可以设置 $defer 变量为 true 来延迟启动,节省开销:
protected $defer = true;
当设置了延迟启动,需要重写 providers 函数。当 Laravel 遇到延迟加载的类,只要在每个 ServiceProvider 中的 providers 函数中搜索制定的引用关键字,便可以调用正确 register 函数的解析该类:
public function providers() {
return [SegmentFault::class];
}
这是笔者的一片文章:PHP Laravel 一个请求的处理过程。(当然因为时间关系还没有写完,待续23333
有错误的地方希望大牛指正,Thx~
以上。