您的位置:首页 > 编程语言 > PHP开发

[置顶] Laravel 框架 容器解析具体的某一个类 的执行 流程

2017-11-11 10:56 495 查看
$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方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐