看了一下Laravel框架对APP的实例化,确实与其它的框架完全不同。大量使用Closure,而且是一层又一层的Closure,之前已经写了一些对Laravel加载vendor的总结,这里写一下加载APP对象的结,Laravel执行到这步还只是实例化了APP对象,并未开始真正的业务操作,业务操作都在Kernel对象里,说说其它的几个框架的源代码吧:
ThinkPhp框架:代码一看就明白,可以这么说,TP框架就是用一堆面向过程的PHP程序堆成了一个功能也不错、使用也方便的框架。
Codeigniter框架:Php框架的起源,初始化各种类然后导入到APP类中,然后在框架里使用$this->db等来操作一切所需要的类,简单,但大道至简吧。
Yii框架:我已经很久没看过YII了,1.1时代看过,那时也没看透,但YII我一直觉得很强大。底层基本无明显缺陷,功能齐全。GII功能没有框架可比。
Laravel框架:非常新,框架的加载过程非常新颖。和其它的框架都很不相同。毕竟Laravel起点很高,起点要求PHP5.4,大量使用新特性。
看一下laravel框架index.php执行完vendor之后加载app.php的代码:
//index.php中执行加载app.php
$app = require_once __DIR__.'/../bootstrap/app.php';
//bootstrap/app.php文件中执行对app的操作
$app = new IlluminateFoundationApplication(
realpath(__DIR__.'/../')
);
$app->singleton(
IlluminateContractsHttpKernel::class,
AppHttpKernel::class
);
$app->singleton(
IlluminateContractsConsoleKernel::class,
AppConsoleKernel::class
);
$app->singleton(
IlluminateContractsDebugExceptionHandler::class,
AppExceptionsHandler::class
);
return $app;
初始化IlluminateFoundationApplication类并传入laravel整体根目录路径。就调用到了vendor/laravel/framework/src/Illuminate/Foundation/Application.php类,这个类文件初始化的过程中主要操作了三个方法:如下:
public function __construct($basePath = null)
{
$this->registerBaseBindings();
$this->registerBaseServiceProviders();
$this->registerCoreContainerAliases();
if ($basePath) {
$this->setBasePath($basePath);
}
}
registerBaseBindings方法处理简单,只是把Application类的静态属性$instance、还有数组属性instances的app键值初始化递归成本类,
registerBaseServiceProviders方法则比较复杂,执行了$this->register(new EventServiceProvider($this));和$this->register(new RoutingServiceProvider($this));两个方法,分别是注册基础events服务和路由等其它服务组件,$this->register(new EventServiceProvider($this));方法所调用的整个过程最重要的在文件:laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php文件约545行里执行的这句:
$provider->register();
而上面这句代码调用的方法执行的是调用Application的singleton方法,将events注册到Application的数组属性bindlings里,如下:
public function register()
{
$this->app->singleton('events', function ($app) {
return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
return $app->make('IlluminateContractsQueueFactory');
});
});
}
上面的代码:(暂时先不要去理会function($app)这个闭包函数的处理,直接看vendor/laravel/framework/src/Illuminate/Container/Container.php中的singleton方法),会调用singleton方法,实际是调用Container.php的bind方法:public function bind($abstract, $concrete = null, $shared = false);并固定传参shared为true。bind方法里两句很重要的代码:
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
$this->bindings[$abstract] = compact('concrete', 'shared');
判断入参$concrete是否是闭包函数,Laravel里所有bind的对象全部要求是闭包函数,如果不是就调用getClosure方法造成闭包函数,方法如下:
protected function getClosure($abstract, $concrete)
{
return function ($c, $parameters = []) use ($abstract, $concrete) {
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete, $parameters);
};
}
可见,如果传入的不是闭包函数,就会将他们转化成一个闭包函数的参数,在闭包函数中通过build或者make方法去调用。注意,$provider->register()这步看起来是执行$provider的方法,实际上是执行Application的方法,并修改Application实例的属性。这样执行后,Application类的bindlings数组属性值就成了如下图:
可以看到bindlings下的组件都要相同的结构,都是由一个闭包函数组件以及是否共享两个组成,而闭包函数组件看似是相同的结构,实际可以根据其中闭包函数调用的不同的类完成的不同的功能。到这里看的都是laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php约545行里执行的这句$provider->register();所执行的功能,而更精妙的这句代码在其后:
$this->markAsRegistered($provider);
此方法的执行程序如下:
protected function markAsRegistered($provider)
{
$this['events']->fire($class = get_class($provider), [$provider]);
$this->serviceProviders[] = $provider;
$this->loadedProviders[$class] = true;
}
几个字码的代码:$this['events'],这里实际上是使用对象数组式访问ArrayAccess的方法,执行了很重要的功能,最终调用了类:vendor/laravel/framework/src/Illuminate/Container/Container.php的offsetGet方法,然后offsetGet里再去调用Container里的make方法来,而在make方法里再调用getConcrete取出bindlings下面events数组里的concrete(如上面的图),这是laravel所有调用make时的操作,就是取出其闭包函数。取出闭包函数后会执行:
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete, $parameters);
} else {
$object = $this->make($concrete, $parameters);
}
isBuildable方法,只要concrere是闭包函数就会执行,所以此处会再调用build方法,而build方法实际就是执行这个闭包函数,代码如下:
public function build($concrete, array $parameters = [])
{
if ($concrete instanceof Closure) {
return $concrete($this, $parameters);
}
...
}
至此实际完成的功能就是在Application类里的instances数组属性值里添加了一个events闭包函数执行后的组件,此处调用的events执行完后,instances数组数据即:IlluminateEventsDispatcher Object如下:
为什么是这个对象,我们可以回头看到在最开始调用$this->register(new EventServiceProvider($this));时实例化的new 类vendor/laravel/framework/src/Illuminate/Events/EventServiceProvider.php中的register方法里执行的是:
return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
return $app->make('IlluminateContractsQueueFactory');
});
所以最终通过$this['events']这个看起来很简单的索引,实际后面完成了组件注册后的实例化。Laravel的Application干的工作就是这样,注册服务组件到Application属性bindings:protected中,而且所有的组件都是一个闭包函数,然后根据需要使用数组索引一下就完成了这个组件的实例化,并写入到数组属性值:instances中。执行完这句后,后面Application的实例化代码功能也都一样了:文章来源:https://www.toymoban.com/news/detail-851373.html
$this->registerBaseServiceProviders();
$this->registerCoreContainerAliases();
上面的第一句代码注册了一些基础服务(比如router,url,redirect等),而registerCoreContainerAliases则是加载了一些类的别名。至此Application类完成了实例化。之后便是Kernel使用Application来创建AppHttpKernel对象,并通过此对象的handle方法来处理请求对象Request,以返回处理结果。文章来源地址https://www.toymoban.com/news/detail-851373.html
到了这里,关于Laravel框架运行机制(四)实例化APP的运行过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!