Laravel5.5源码详解 -- Config 配置文件的加载
Laravel5.5源码详解 – Config 配置文件的加载细节
关于大框架的分析,网上已经有比较多的资料,那些资料大体上只告诉我们这个函数是干嘛的,那个函数是干嘛的,但具体如何走都没有介绍,所以我这里主要从细节看程序的具体流向。
首先从/public/index.php开始,程序正是从这里启动的。
$app = require_once __DIR__.'/../bootstrap/app.php';
这里,$app得到Bootstrap\app.php,其中Kernel类会被 绑定到容器container中。
<?php
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
//----------Kernel就是这里被绑定的---------------------
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
return $app;
随后,实现$Kernel,
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
Illuminate\Contracts\Http\Kernel只是一个接口,由其继承者Illuminate\Foundation\Http\Kernel实现。这里创建了,也正是这个类。
随后,
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
调用Kernel类的Handle函数,处理传送进来的request,代码和注释如下,
public function handle($request)
{
try {
$request->enableHttpMethodParameterOverride();
//----------下面调用了sendRequestThroughRouter函数来发送request------------
$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);
}
$this->app['events']->dispatch(
new Events\RequestHandled($request, $response)
);
return $response;
}
protected function sendRequestThroughRouter($request)
{
$this->app->instance('request', $request);
Facade::clearResolvedInstance('request');
//------------这里开始调用bootrap函数配置参数。-----------------
$this->bootstrap();
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
}
public function bootstrap()
{
if (! $this->app->hasBeenBootstrapped()) {
//------------直接调用app的bootstrapWith()-------------------
$this->app->bootstrapWith($this->bootstrappers());
}
}
bootstrapWith会生成所需要的对象,其参数正是Illuminate\Foundation\Http\Kernel中的$bootstrappers中列出的类,第二条就是我们要关注的配置参数时要用到的类,
protected $bootstrappers = [
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
\Illuminate\Foundation\Bootstrap\HandleExceptions::class,
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
\Illuminate\Foundation\Bootstrap\RegisterProviders::class,
\Illuminate\Foundation\Bootstrap\BootProviders::class,
];
$app中的配置函数bootstrapWith()函数的原型如下,
public function bootstrapWith(array $bootstrappers)
{
$this->hasBeenBootstrapped = true;
foreach ($bootstrappers as $bootstrapper) {
$this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);
//------这里,在处理LoadConfiguration类时,会直接调用其中的bootstrap------
$this->make($bootstrapper)->bootstrap($this);
$this['events']->fire('bootstrapped: '.$bootstrapper, [$this]);
}
}
上面我们看到,app会在生成LoadConfiguration对象后,直接调用其bootstrap()函数来进行相关配置。所以,最终的config 配置文件是由类 \Illuminate\Foundation\Bootstrap\LoadConfiguration::class 完成的,详细注释如下,
public function bootstrap(Application $app)
{
$items = [];
if (file_exists($cached = $app->getCachedConfigPath())) {
//注意,这个$cached返回的是路径,
//"D:\wamp64\www\laravel\larablog\bootstrap/cache/config.php"
$items = require $cached;
//items就相当于/bootstrap/cache/config.php里面的所有配置项
$loadedFromCache = true;
}
//下面,new Repository($items)创建一个仓库,并把所有配置项作为参数传递进去,
//然后绑定到$app->instances数组中的config上,说明config已经实例化。
$app->instance('config', $config = new Repository($items));
//此时,如果打印出$app,就会得到后面的那些内容,可以明显看到,
//instances数组中添加了’config’ (已经刻意展开了该项)
if (! isset($loadedFromCache)) {
$this->loadConfigurationFiles($app, $config);
}
$app->detectEnvironment(function () use ($config) {
return $config->get('app.env', 'production');
});
date_default_timezone_set($config->get('app.timezone', 'UTC'));
mb_internal_encoding('UTF-8');
}
dd(#app)得到的结果,
Application {#2 ▼
...
#instances: array:17 [▼
...
"events" => Dispatcher {#26 ▶}
"router" => Router {#25 ▶}
"Illuminate\Contracts\Http\Kernel" => Kernel {#29 ▶}
"request" => Request {#42 ▶}
"config" => Repository {#24 ▶}
]
...
}
这个配置,在各个模块的理解中都要用到,比如在session的启动中getDefaultDriver()中拉出来用的配置。
当然,有兴趣的朋友可以继续研究loadConfigurationFiles。它主要是在缓存不存在时,才会被调用来加载配置文件。我在使用时,一般会通过php artisan config:cache命令来生成配置文件到bootstrap/cache/config.php,所以后面的loadConfigurationFiles不会运行。