Laravel 框架 容器解析具体的某一个类 的执行 流程
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);以laravel 框架中入口文件的一行代码进行分析。由于Illuminate\Contracts\Http\Kernel::class 绑定的具体的类为App\Http\Kernel ,所以其实就是对App\Http\Kernel的解析,结合http://blog.cs
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
以laravel 框架中入口文件的一行代码进行分析。由于Illuminate\Contracts\Http\Kernel::class 绑定的具体的类为App\Http\Kernel ,所以其实就是对App\Http\Kernel的解析,结合http://blog.csdn.net/qq_16877261/article/details/78053512 这篇文章,我们直接从容器中 build函数进行分析。
/** * Instantiate a concrete instance of the given type. * 实例化一个具体的对象 * @param 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 // used as resolvers for more fine-tuned resolution of these objects. //是否是闭包(匿名函数) 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(); if($concrete == 'App\Http\Kernel'){ dd($dependencies); } // 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); }
打印$dependencies 结果如下:
这里利用了PHP的反射类获取 所要实例化类的构造函数的参数。在laravel中,构造函数中一般会使用依赖注入,所以在获取的参数中包含有依赖的类,应该如何处理呢?
laravel 中 在resolveDependencies函数进行了处理。
/** * Resolve all of the dependencies from the ReflectionParameters. * * @param array $dependencies * @return array */ protected function resolveDependencies(array $dependencies) { $results = []; foreach ($dependencies as $dependency) { // If the class is null, it means the dependency is a string or some other // primitive type which we can not resolve since it is not a class and // we will just bomb out with an error since we have no-where to go. $results[] = is_null($class = $dependency->getClass()) ? $this->resolvePrimitive($dependency) : $this->resolveClass($dependency);//参数 如果依赖的是一个类,会执行这个 } //函数,解析依赖的类。这就是依赖注入 return $results; //原理,发现很简单啊 }最后根据给出的参数实例化类。在本例中就是App\Http\Kernel。于是我们就去查看这个类,发现这个类只有三个属性数组,当然你不知道它们是用来做什么的,于是查看父类
Illuminate\Foundation\Http\Kernel 。父类的构造函数中没有特别的操作(只是进行一些属性的操作和一些中间件的注册),可以自行查看。至此该类的实例化完成。
于是我们接着查看入口文件
$response = $kernel->handle( $request = Illuminate\Http\Request::capture() );
所以接着查看Illuminate\Foundation\Http\Kernel中的handle函数。
public function handle($request) { try { $request->enableHttpMethodParameterOverride(); $response = $this->sendRequestThroughRouter($request); } catch (Exception $e) { $this->reportException($e); $response = $this->renderException($request, $e); } catch (Throwable $e) { $this->reportException($e = new FatalThrowableError($e)); $response = $this->renderException($request, $e); } event(new Events\RequestHandled($request, $response)); return $response; }
查看这个函数发现我只需要看sendRequestThroughRouter 这个函数就可以了。
protected function sendRequestThroughRouter($request) { // 实例化一个已经存在的实例 $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); $this->bootstrap(); return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); }我们查看bootstrap,又去查看bootstrapWith 函数如下:
public function bootstrapWith(array $bootstrappers)
{
$this->hasBeenBootstrapped = true;
//dd($this['events']);
foreach ($bootstrappers as $bootstrapper) {
//events 对应绑定的类为 Dispatcher类
$this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);
// 从容器解析引导类,并且执行引导类的bootstrap方法
$this->make($bootstrapper)->bootstrap($this); $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]); }}
又查看fire函数如下:
public function fire($event, $payload = [], $halt = false) { return $this->dispatch($event, $payload, $halt); }最终查看dispatch 函数如下:
public function dispatch($event, $payload = [], $halt = false) { // When the given "event" is actually an object we will assume it is an event // object and use the class as the event name and this event itself as the // payload to the handler, which makes object based events quite simple. list($event, $payload) = $this->parseEventAndPayload( $event, $payload ); //引导程序不执行这部分 if ($this->shouldBroadcast($payload)) { $this->broadcastEvent($payload[0]); } $responses = []; // dd($this->getListeners($event)); //引导程序不执行这部分 foreach ($this->getListeners($event) as $listener) { $response = $listener($event, $payload); // If a response is returned from the listener and event halting is enabled // we will just return this response, and not call the rest of the event // listeners. Otherwise we will add the response on the response list. if (! is_null($response) && $halt) { return $response; } // If a boolean false is returned from a listener, we will stop propagating // the event to any further listeners down in the chain, else we keep on // looping through the listeners and firing every one in our sequence. if ($response === false) { break; } $responses[] = $response; } return $halt ? null : $responses; }发现引导类第一次执行后返回是一个空数组。
于是 $this->bootstrap(); 这句其实就是执行对应引导类的bootstrap方法。
最后关于管道的理解请参考
http://www.jianshu.com/p/3c2791a525d0
zheyu方法
更多推荐
所有评论(0)