本篇文章给大家带来的内容是关于laravel服务容器的绑定与解析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
前言
老实说,第一次老大让我看laravel框架手册的那天早上,我是很绝望的,因为真的没接触过,对我这种渣渣来说,laravel的入门门槛确实有点高了,但还是得硬着头皮看下去(虽然到现在我还有很多没看懂,也没用过)。
后面慢慢根据公司项目的代码对laravel也慢慢熟悉起来了,但还是停留在一些表面的功能,例如依赖注入,orm操作,用户认证这些和我项目业务逻辑相关的操作,然后对于一些架构基础的,例如服务提供器,服务容器,中间件,redis等这些一开始就要设置好的东西,我倒是没实际操作过(因为老大一开始就做好了),所以看手册还是有点懵。
所以有空的时候逛逛论坛,搜下google就发现许多关于laravel核心架构的介绍,以及如何使用的网站(确实看完后再去看手册就好理解多了),下面就根据一个我觉得不错的网站上面的教学来记录一下laravel核心架构的学习
网站地址:/d/file/titlepic/ 这是一个日本的网站,我觉得挺适合新手的,内容用浏览器翻译过来就ok了,毕竟日文直翻过来很好理解的
关于服务容器
手册上是这样介绍的:laravel 服务容器是用于管理类的依赖和执行依赖注入的工具。依赖注入这个花俏名词实质上是指:类的依赖项通过构造函数,或者某些情况下通过「tter」方法「注入」到类中。。。。。。(真的看不懂啥意思)
服务容器是用于管理类(服务)的实例化的机制。直接看看服务容器怎么用
1.在服务容器中注册类(bind)
1
2
$this
->app->bind(
'nder'
,
'mailnder'
);
//$this->app成为服务容器。
2.从服务容器生成类(make)
1
2
3
$nder
=
$this
->app->make(
'nder'
);
//从服务容器($this->app)创建一个nder类。
在这种情况下,将返回mailnder的实例。
这是服务容器最简单的使用,下面是对服务容器的详细介绍
laravel容器基本认识
一开始,index.php 文件加载 compor 生成定义的自动加载器,然后从 bootstrap/app.php 脚本中检索 laravel 应用程序的实例。laravel 本身采取的第一个动作是创建一个 application/ rvice container 的实例。
1
2
3
$app
=
new
illuminate\foundation\application(
dirname(__dir__)
);
这个文件在每一次请求到达laravel框架都会执行,所创建的$app即是laravel框架的应用程序实例,它在整个请求生命周期都是唯一的。laravel提供了很多服务,包括认证,数据库,缓存,消息队列等等,$app作为一个容器管理工具,负责几乎所有服务组件的实例化以及实例的生命周期管理。当需要一个服务类来完成某个功能的时候,仅需要通过容器解析出该类型的一个实例即可。从最终的使用方式来看,laravel容器对服务实例的管理主要包括以下几个方面:
服务的绑定与解析
服务提供者的管理
别名的作用
依赖注入
先了解如何在代码中获取到容器实例,再学习上面四个关键
第一种是
1
2
3
4
$app
= app();
//app这个辅助函数定义在\vendor\laravel\framework\src\illuminate\foundation\helper.php
里面,,这个文件定义了很多help函数,并且会通过compor自动加载到项目中。
所以,在参与http请求处理的任何代码位置都能够访问其中的函数,比如app()。
第二种是
1
2
3
4
5
6
7
route::get(
'/'
,
function
() {
dd(app::bapath());
英雄的故事
return
''
;
});
//这个其实是用到facade,中文直译貌似叫门面,在config/app.php中,
有一节数组alias专门用来配置一些类型的别名,第一个就是
'app'
=> illuminate\support\facades\app::
class
,
具体的google一下laravel有关门面的具体实现方式
第三种是
在服务提供者里面直接使用$this->app。服务提供者后面还会介绍,现在只是引入。因为服务提供者类都是由laravel容器实例化的,这些类都继承自illuminate\support\rviceprovider,它定义了一个实例属性$app:
1
2
3
abstract
class
rviceprovider
{
protected
$app
;
laravel在实例化服务提供者的时候,会把laravel容器实例注入到这个$app上面。所以我们在服务提供者里面,始终能通过$this->$app访问到laravel容器实例,而不需要再使用app()函数或者app facade了。
浅义层面理解,容器既然用来存储对象,那么就要有一个对象存入跟对象取出的过程。这个对象存入跟对象取出的过程在laravel里面称为服务的绑定与解析。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
app()->bind(
'rvice'
,
'this is rvice1'
);
app()->bind(
'rvice2'
, [
'hi'
=>
function
(){
//say hi
}
]);
class
rvice {
}
app()->bind(
'rvice3'
,
function
(){
return
new
rvice();
});
还有一个单例绑定singleton,是bind的一种特殊情况(第三个参数为true),绑定到容器的对象只会被解析一次,之后的调用都返回相同的实例
1
2
3
4
public
function
singleton(
$abstract
,
$concrete
= null)
{
$this
->bind(
$abstract
,
$concrete
, true);
}
在绑定的时候,我们可以直接绑定已经初始化好的数据(基本类型、数组、对象实例),还可以用匿名函数来绑定。用匿名函数的好处在于,这个服务绑定到容器以后,并不会立即产生服务最终的对象,只有在这个服务解析的时候,匿名函数才会执行,此时才会产生这个服务对应的服务实例。
实际上,当我们使用singleton,bind方法以及数组形式,(这三个方法是后面要介绍的绑定的方法),进行服务绑定的时候,如果绑定的服务形式,不是一个匿名函数,也会在laravel内部用一个匿名函数包装起来,这样的话, 不轮绑定什么内容,都能做到前面介绍的懒初始化的功能,这对于容器的性能是有好处的。这个可以从bind的源码中看到一些细节:
1
2
3
if
(!
$concrete
instanceof
closure) {
$concrete
=
$this
->getclosure(
$abstract
,
$concrete
);
}
看看bind的底层代码
1
public
function
bind(
$abstract
,
$concrete
= null,
$shared
= fal)
第一个参数服务绑定名称,第二个参数服务绑定的结果(也就是闭包,得到实例),第三个参数就表示这个服务是否在多次解析的时候,始终返回第一次解析出的实例(也就是单例绑定singleton)。
服务绑定还可以通过数组的方式:
1
2
3
app()[
'rvice'
] =
function
(){
return
new
rvice();
};
绑定大概就这些,接下来看解析,也就是取出来用
1
$rvice
= app()->make(
'rvice'
);
这个方法接收两个参数,第一个是服务的绑定名称和服务绑定名称的别名,如果是别名,那么就会根据服务绑定名称的别名配置,找到最终的服务绑定名称,然后进行解析;第二个参数是一个数组,最终会传递给服务绑定产生的闭包。
看源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* resolve the given type from the container.
*
* @param string $abstract
* @param array $parameters
* @return mixed
*/
public
function
make(
$abstract
,
array
$parameters
= [])
{
return
$this
->resolve(
$abstract
,
$parameters
);
}
/**
* resolve the given type from the container.
*
* @param string $abstract
* @param退档 array $parameters
* @return mixed
*/
protected
function
resolve(
$abstract
,
$parameters
= [])
{
$abstract
=
$this
->getalias(
$abstract
);
$needscontextualbuild
= !
empty
(
$parameters
) || !
is_null
(
$this
->getcontextualconcrete(
$abstract
)
);
// if an instance of the type is currently being managed as a singleton we'll
// just return an existing instance instead of instantiating new instances
// so the developer can keep using the same objects instance every time.
if
(ist(
$this
->instances[
$abstract
]) && !
$needscontextualbuild
) {
return
$this
->instances[
$abstract
];
}
$this
->with[] =
$parameters
;
$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
)) {
$object
=
$this
->build(
$concrete
);
}
el
{
$object
=
$this
->make(
$concrete
);
}
// if we defined any extenders for this type, we'll need to spin through them
// and apply them to the object being built. this allows for the extension
// of rvices, such as changing configuration or decorating the object.
foreach
(
$this
->getextenders(
$abstract
)
as
$extender
) {
$object
=
$extender
(
$object
,
$this
);
}
// if the requested type is registered as a singleton we'll want to cache off
// the instances in "memory" so we can return it later without creating an
// entirely new instance of an object on each subquent request for it.
if
(
$this
->isshared(
$abstract
) && !
$needscontextualbuild
) {
$this
->instances[
$abstract
] =
$object
;
}
$this
->fireresolvingcallbacks(
$abstract
,
$object
);
// before returning, we will also t the resolved flag to "true" and pop off
// the parameter overrides for this build. after tho two things are done
// we will be ready to return back the fully constructed class instance.
$this
->resolved[
$abstract
] = true;
array_pop
(
$this
->with);
return
$object
;
}
第一步:
1
2
3
$needscontextualbuild
= !
empty
(
$parameters
) || !
is_null
(
$this
->getcontextualconcrete(
$abstract
)
);
该方法主要是区分,解析的对象是否有参数,如果有参数,还需要对参数做进一步的分析,因为传入的参数,也可能是依赖注入的,所以还需要对传入的参数进行解析;这个后面再分析。
第二步:
1
2
3
if
客服主管(ist(
$this
->instances[
$abstract
]) && !
$needscontextualbuild
) {
return
$this
->instances[
$abstract
];
}
如果是绑定的单例,并且不需要上面的参数依赖。我们就可以直接返回 $this->instances[$abstract]。
第三步:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$concrete
=
$this
导数求导公式->getconcrete(
$abstract
);
...
/**
* get the concrete type for a given abstract.
*
* @param string $abstract
* @return mixed $concrete
*/
protected
function
getconcrete(
$abstract
)
{
if
(!
is_null
(
$concrete
=
$this
->getcontextualconcrete(
$abstract
))) {
return
$concrete
;
}
// if we don't have a registered resolver or concrete for the type, we'll just
// assume each type is a concrete name and will attempt to resolve it as is
// since the container should be able to resolve concretes automatically.
if
(ist(
$this
->bindings[
$abstract
])) {
return
$this
->bindings[
$abstract
][
'concrete'
];
}
return
$abstract
;
}
这一步主要是先从绑定的上下文找,是不是可以找到绑定类;如果没有,则再从 $bindings[] 中找关联的实现类;最后还没有找到的话,就直接返回 $abstract 本身。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 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
)) {
$object
=
$this
->build(
$concrete
);
}
el
{
$object
=
$this
->make(
$concrete
);
}
...
/**
* determine if the given concrete is buildable.
*
* @param mixed $concrete
* @param string $abstract
* @return bool
*/
protected
function
isbuildable(
$concrete
,
$abstract
)
{
return
$concrete
===
$abstract
||
$concrete
instanceof
closure;
}
如果之前找到的 $concrete 返回的是 $abstract 值,或者 $concrete 是个闭包,则执行 $this->build($concrete),否则,表示存在嵌套依赖的情况,则采用递归的方法执行 $this->make($concrete),直到所有的都解析完为止。
$this->build($concrete)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* instantiate a concrete instance of the given type.
*
* @para宜宾学院m string $concrete
* @return mixed
*
* @throws \illuminate\contracts\container\bindingresolutionexception
*/
public
function
build(
$concrete
)
{
// if the concrete type is actually a closure, we will just execute it and
// hand back the results of the functions, which allows functions to be
// ud as resolvers for more fine-tuned resolution of the objects.
// 如果传入的是闭包,则直接执行闭包函数,返回结果
if
(
$concrete
instanceof
closure) {
return
$concrete
(
$this
,
$this
->getlastparameteroverride());
}
// 利用反射机制,解析该类。
$reflector
=
new
reflectionclass(
$concrete
);
// if the type is not instantiable, the developer is attempting to resolve
// an abstract type such as an interface of abstract class and there is
// no binding registered for the abstractions so we need to bail out.
if
(!
$reflector
->isinstantiable()) {
return
$this
->notinstantiable(
$concrete
);
}
$this
->buildstack[] =
$concrete
;
// 获取构造函数
$constructor
=
$reflector
->getconstructor();
// if there are no constructors, that means there are no dependencies then
// we can just resolve the instances of the objects right away, without
// resolving any other types or dependencies out of the containers.
// 如果没有构造函数,则表明没有传入参数,也就意味着不需要做对应的上下文依赖解析。
if
(
is_null
(
$constructor
)) {
// 将 build 过程的内容 pop,然后直接构造对象输出。
array_pop
(
$this
->buildstack);
return
new
$concrete
;
}
// 获取构造函数的参数
$dependencies
=
$constructor
->getparameters();
// once we have all the constructor's parameters we can create each of the
// dependency instances and then u the reflection instances to make a
// new instance of this class, injecting the created dependencies in.
// 解析出所有上下文依赖对象,带入函数,构造对象输出
$instances
=
$this
->resolvedependencies(
$dependencies
);
array_pop
(
$this
->buildstack);
return
$reflector
->newinstanceargs(
$instances
);
}
本文发布于:2023-04-07 19:46:46,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/46de40717c7078c46c112821fff283e7.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:Laravel服务容器的绑定与解析.doc
本文 PDF 下载地址:Laravel服务容器的绑定与解析.pdf
留言与评论(共有 0 条评论) |