Laravel 容器解析
laravel容器laravel容器负责存放所需要的各种类,当需要的时候再从容器中解析。下面我们对容器进行分析,如果有谬误,欢迎指正。入口文件laravel入口文件在public目录下面的index.php。然后进入index.php。require __DIR__.'/../bootstrap/autoload.php';$app = require_once __DIR__.'/../b
laravel容器
laravel容器负责存放所需要的各种类,当需要的时候再从容器中解析。下面我们对容器进行分析,如果有谬误,欢迎指正。
入口文件
laravel入口文件在public目录下面的index.php。然后进入index.php。
require __DIR__.'/../bootstrap/autoload.php'; $app = require_once __DIR__.'/../bootstrap/app.php';类的自动加载可以看我的另一篇博文: http://blog.csdn.net/qq_16877261/article/details/77707453
查看app.php代码如下,然后进入laravel容器。
$app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') );
直接查看容器的构造函数如下:
注册路径
public function __construct($basePath = null) { if ($basePath) { $this->setBasePath($basePath); } //注册容器基本实例 $this->registerBaseBindings(); $this->registerBaseServiceProviders(); //注册核心的容器类别名 $this->registerCoreContainerAliases(); }首先我们先查看setBasePath 这个函数,最终发现通过bindPathsInContainer这个函数将一些常用的路径绑定到容器。关于绑定函数instance 请查看博文:http://blog.csdn.net/qq_16877261/article/details/78189673
instance 绑定其实就是将绑定的对象放入容器中的$instances 数组中,我打印这个数组结果如下,发现laravel绑定路径其实和其他框架里将路径定义为常量的效果是一样的。
绑定容器实例
接着我看下一个函数registerBaseBindings,代码如下:
在该方法中,首先将当前的类设置为全局的容器实例,然后将app与容器实例进行绑定,方便以后通过访问app属性来访问容器。最后将Container类的访问也绑定到容器实例。
绑定所谓的服务提供者
找到 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. * 绑定到容器的对象只会被解析一次,之后的调用都返回相同的实例: * @param string|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 如下
即 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. * * 从容器中解析实例 * @param string $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);}
更多推荐
所有评论(0)