参考
https://laravelacademy.org/po...
https://laravelacademy.org/po...
服务容器
控制反转(IOC)与依赖注入(DI)
讲的都是1个概念.
Ioc: 主对象依赖的某些对象原来在对象内部产生.现在把这个动作放到外面,比如Ioc容器,,IoC容器控制了对象生命周期,需要对象时,直接找容器,容器实例负责查找及创建依赖对象(也可以直接绑定已有对象的实例).
DI 由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台, 这个平台就是基于IOC容器.
注入的原理是反射
,根据类名创建实例,或者是Clouse
,即闭包函数创建实例.
所以容器需要知道它负责的对象如何创建,这就是bind(绑定创建实例的闭包函数)和instance(绑定已有实例)的作用.
如何保存绑定大量对象?,就用array数组搞定:
#bind绑定后的binding数组:
[
'A\1': 返回new的闭包函数 or 具体实现类 or 类名
'A\2': 返回new的闭包函数 or 具体实现类 or 类名
]
#如果是`singleton`方法,实例存在instances数组,供下次使用.
[
'A\1': A\1实例,
'A\2': A\2实例
]
有了绑定关系,剩下的就是如何解析实例了,函数build
,make
,resolve
等.
//container.php
$concrete = $this->getConcrete($abstract);
// We're ready to instantiate an instance of the concrete type registered for
// the binding. This will instantiate the types, as well as resolve any of
// its "nested" dependencies recursively until all have gotten resolved.
if ($this->isBuildable($concrete, $abstract)) {
//build
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
最终的核心动作在build
里, 如果concrete是closure,则调用产生,否则根据类名反射
产生该实例
反射里应该是一颗递归树,因为class A的constructor参数里, 可能依赖B,B依赖C,D...
public function build($concrete)
{
//...
if ($concrete instanceof Closure) {
return $concrete($this, $this->getLastParameterOverride());
}
try {
$reflector = new ReflectionClass($concrete);
} catch (ReflectionException $e) {
throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
}
//...
}
bind的基本原理就这样了,而singleton是单例模式,生成的单例存储会先存储到instance数组.
服务提供者
所有类都这样手动bind,当然麻烦,于是就有service provider
.
先register Provider, 它会调用每个Provider实例里的register和boot,完成具体的实例bind.
public function register($provider, $force = false)
{
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
// If the given "provider" is a string, we will resolve it, passing in the
// application instance automatically for the developer. This is simply
// a more convenient way of specifying your service provider classes.
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
$provider->register();
// If there are bindings / singletons set as properties on the provider we
// will spin through them and register them with the application, which
// serves as a convenience layer while registering a lot of bindings.
if (property_exists($provider, 'bindings')) {
foreach ($provider->bindings as $key => $value) {
$this->bind($key, $value);
}
}
if (property_exists($provider, 'singletons')) {
foreach ($provider->singletons as $key => $value) {
$this->singleton($key, $value);
}
}
$this->markAsRegistered($provider);
// If the application has already booted, we will call this boot method on
// the provider class so it has an opportunity to do its boot logic and
// will be ready for any usage by this developer's application logic.
if ($this->isBooted()) {
$this->bootProvider($provider);
}
return $provider;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。