1. 云栖社区>
  2. PHP教程>
  3. 正文

Laravel 服务容器解析

作者:用户 来源:互联网 时间:2017-11-30 20:45:58

laravel容器解析服务

Laravel 服务容器解析 - 摘要: 本文讲的是Laravel 服务容器解析,public function __construct($basePath = null){if ($basePath) {$this->setBasePath($basePath);}//注册容器基本实例$this->regi

public function __construct($basePath = null)
{
if ($basePath) {
$this->setBasePath($basePath);
}//注册容器基本实例
$this->registerBaseBindings();
$this->registerBaseServiceProviders();$this->registerCoreContainerAliases();
}注册一个单例

找到 registerBaseServiceProviders函数如下

protected function registerBaseServiceProviders()
{
$this->register(new EventServiceProvider($this));
$this->register(new LogServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
}
以EventServiceProvider 为例,然后查看register函数如下
public function register($provider, $options = [], $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);
}
//通过这一步实现服务提供者的绑定,然后查看具体服务提供者的//register 函数if (method_exists($provider, 'register')) {$provider->register();}$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->booted) {$this->bootProvider($provider);}return $provider;}

EventServiceProvider 类下的register函数如下

public function register()
{
$this->app->singleton('events', function ($app) {
return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
return $app->make(QueueFactoryContract::class);
});
});
}
于是我们去查看容器中的singleton 函数如下,发现singleton函数其实只是bind函数最后一个参数为为true。/**
* Register a shared binding in the container.
*绑定到容器的对象只会被解析一次,之后的调用都返回相同的实例:
* @paramstring|array$abstract
* @param/Closure|string|null$concrete
* @return void
*/
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}

于是查看bind函数如下:

public function bind($abstract, $concrete = null, $shared = false)
{
// If no concrete type was given, we will simply set the concrete type to the
// abstract type. After that, the concrete type to be registered as shared
// without being forced to state their classes in both of the parameters.//移除旧的实例
$this->dropStaleInstances($abstract);
if (is_null($concrete)) {
$concrete = $abstract;
}
// If the factory is not a Closure, it means it is just a class name which is
// bound into this container to the abstract type and we will just wrap it
// up inside its own Closure to give us more convenience when extending.
if (! $concrete instanceof Closure) {// 绑定的时候,如果$concrete 是具体的类名,通过下面的函数封装成闭包
闭包里面的内容一般是这样的return$this->make($concrete);或者$this->build($concrete);
$concrete = $this->getClosure($abstract, $concrete);
}
// 创建一个包含变量与其值的数组。
//对每个参数,compact() 在当前的符号表中查找该变量名并将它添加到输出的数组中,变量名成为键名而变量的内容成为该键的值。简单说,它做的事和 extract() 正好相反。返回将所有变量添加进去后的数组。
$this->bindings[$abstract] = compact('concrete', 'shared');// If the abstract type was already resolved in this container we'll fire the
// rebound listener so that any objects which have already gotten resolved
// can have their copy of the object updated via the listener callbacks.
//检查是否解析过 或则 已经存在所要绑定对象对应的实例if ($this->resolved($abstract)) {$this->rebound($abstract);}}
由于events 是第一次绑定,不会进行 $this->rebound($abstract); 最后singleton 函数执行后的结果是 打印$this->bindings 如下

Laravel 服务容器解析-


即 singleton 函数 在对象第一次进行绑定时,只是进行对象的绑定,而不会执行额外的操作,例如 不会对绑定的匿名函数进行执行。


服务容器解析

下面我们分析下对象的解析,以入口文件这行代码进行讲解


dd(


Illuminate/Contracts/Http/Kernel::class
) // Illuminate/Contracts/Http/Kernel 绑定的类名为
"App/Http/Kernel"
$kernel = $app->make(Illuminate/Contracts/Http/Kernel::class);make 函数如下
/**
* Resolve the given type from the container.
*
*从容器中解析实例
* @paramstring$abstract
* @return mixed
*/
public function make($abstract)
{
$needsContextualBuild = ! is_null(
$this->getContextualConcrete($abstract = $this->getAlias($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 (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
return $this->instances[$abstract];
}//获取具体实现,一般从容器中的$this->bingdings 数组中获取,如果没有,直接返回类名
$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);
} else {
$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 services, 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 subsequent request for it.
if ($this->isShared($abstract) && ! $needsContextualBuild) {
$this->instances[$abstract] = $object;
}$this->fireResolvingCallbacks($abstract, $object);$this->resolved[$abstract] = true;return $object;
}
按照程序执行,由于是第一次解析,执行

$this->build($concrete); 于是我又去查看build函数

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
// used as resolvers for more fine-tuned resolution of these objects.
//是否是闭包(匿名函数),在本例中由于是闭包,就直接返回闭包执行的结果。由于这个闭包是自动封装的闭包,格式如下
// $this->make($concrete);其实就是直接解析绑定的类,在本例中就是App/Http/Kernel 于是又需要查看make函数if ($concrete instanceof Closure) {
return $concrete($this);
}$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 these containers.
if (is_null($constructor)) {
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 use 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);}


















































































以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索laravel , 容器 , 解析 服务 ,以便于您获取更多的相关知识。