从 Laravel 代码理解 IoC

IOC 容器

把 Laravel 容器方面所了解的知识总结了下,语言组织能力比较弱,如有错误的、不恰当的地方还请@我。

入口文件 index.php

1、加载框架依赖
2、创建 app 容器
3、解析 Http\Kernel.php 内核
4、执行请求操作
5、返回结果
6、终止应用程序

file

app.php 文件(require_once DIR.'/../bootstrap/app.php')

1、创建容器
2、绑定 Http\Hernel.php 到容器
3、绑定 Console\Kernel.php 到容器
4、绑定 Exception\Hadnler.php 到容器
5、返回 app 容器

file

app 容器

打印 app 容器

1、serviceProviders 属性
    用于存放所有已经注册完毕的服务提供者

2、loadedProviders 属性
    跟 serviceProviders 数组类似,标记方式不同

3、deferredServices 属性
    用来储存所有延迟加载服务提供者

4、resolved 属性
    服务解析完毕,都会在 resolved 属性里面存入一条记录,表示绑定已经解析过

5、bindings 属性
    记录所有绑定

6、instances 属性
    在第一次解析绑定时,如果 shared 为 true则都会往 instances 属性里面存入一条记录

7、aliases 属性
    服务绑定的别名,别名数量无限制

file

注册服务提供者

注册服务提供者只需要继承 ServiceProvider 抽象类即可(放在那儿都可以),并在 config/app.php providers 数组
里面注册或使用 app()->register(TestProvider::class)(此方法 $defer 属性无效) 即可

1、继承 ServiceProvider 抽象类

2、创建 register 方法并使用 app 容器绑定服务(可绑定任意数量服务)

3、创建 boot 方法,初始化所绑定的服务

4、$defer 属性为是否延迟加载,为 true 会存入到 deferredServices 属性,程序注册时会调用 ServicePr
    ovider 抽象类的 isDeferred() 方法 『必须在config/app.php providers中注册』

5、事件触发注册服务提供者,ServiceProvider 抽象类的 when 方法返回一个数组,数组里面包含事件
    名称 如:[TestEvent::class],『$defer 必须为 true』

注意:
    PHP 在处理请求前,都会从入口文件把所有 PHP 文件都扫描一遍。Laravel 为了性能考虑,会在第一
    次初始化的时候,把所有服务提供者都缓存到 bootstrap/cache/service.php 文件里面,所以有时候在
    改或增了服务提供者,刷新可能不生效,这有可能是缓存所致,这时把 service.php 与 packages.php
    删除再重试

注册服务提供者别名

app()->alias('testProvider','test') 别名数量无限制

file

app 容器绑定

1、app()->bind($abstract, $concrete = null, $shared = false)
第一个参数是服务绑定名称,第二个参数是绑定结果(参数类型:\Closure|string|null),第三个参数是否共享(类似
单例),默认为 false,第二个参数,如果是非闭包,内部会包裹上闭包,好处是延迟加载,节约空间

file

2、app()->singleton($abstract, $concrete = null)
第一个参数是服务绑定名称,第一个参数是绑定结果,在内部是调用了 app()->bind($abstract, $concrete = null, true),
第三个参数为 true

file

3、app()['test'] = function(){ return 'test' }
使用了 PHP ArrayAccess 接口,在内容调用了 app()->bind() 方法,第三个参数为 false

file
file

4、app()->instance('test',实例)
绑定一个实例,跟上面三个比,就是少了一个闭包

app 容器解析

1、app($abstract, $parameters = [])
    第一个参数是服务绑定的名称或别名,第二个参数为上下文名称或别名

2、app()->make($abstract, $parameters = [])
    同上

3、app()[$abstract]
    只有第一个参数,使用了 PHP ArrayAccess 接口

DI 依赖注入

DI 是 IOC 的一种实现,DI 是一种设计模式,IOC 是一种设计思想,DI 实现原理是使用 PHP 反射机制来反射出相应依赖对
象名称,通过 aliases 属性得到服务名称,然后从容器解析出服务实例,最后传入对应方法,这个过程就是所谓的依赖注入

file
file

总结

Laravel 是一个组件式框架,实现了高度解耦,再使用 IOC 容器来管理解耦后的组件,我把这个容器理解为使用了对象的高级注册树,当组件越来越多时,那么这个容器对象不是越来越大吗?所以 Laravel 使用了闭包来延迟加载,但是有个问题,如果每次获取都去 new 一次,不是很浪费时间与空间吗?在能满足需求的情况下,能不能只 new 一次(类似单例),所以 Laravel 又引入了 shared 来实现单例,用 instances 属性来保存单例(服务在生命周期内,shared 不可更改,而且 Laravel 大部分服务 shared 都为 true),现在又有个需求,当某个动作发生时,就触发服务加载?所以 Laravel 又加入了 when 方法来绑定事件,前提是这个服务 shared 必须为 true。

光年之外
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 3

感觉好复杂

7年前 评论

@mingyun 感觉复杂在那里,是那个地方让你感觉很不好理解。

7年前 评论

哇 看得似懂非懂 但是感觉好牛逼

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!