$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方法
来源: http://blog.csdn.net/qq_16877261/article/details/78189673