同志们,这章我们来看一哈: Laravel
中 config
的加载原理。
上一章说过,Laravel
启动引导,无非就是循环实例化$bootstrappers
数组中的类,并调用类的 bootstrap
方法。
[
](https://lccdn.phphub.org/uploads/images/201809/27/27709/35joJy2Y35.png?imageView2/2/w/1240/h/0)
如图,这一章介绍划红线的 bootstrap
方法。
先把 bootstrap
方法贴出来,我们一起来看看它长什么样
public function bootstrap(Application $app)
{
$items = [];
// First we will see if we have a cache configuration file. If we do, we'll load
// the configuration items from that file so that it is very quick. Otherwise
// we will need to spin through every configuration file and load them all.
if (file_exists($cached = $app->getCachedConfigPath())) {
$items = require $cached;
$loadedFromCache = true;
}
// Next we will spin through all of the configuration files in the configuration
// directory and load each one into the repository. This will make all of the
// options available to the developer for use in various parts of this app.
$app->instance('config', $config = new Repository($items));
if (! isset($loadedFromCache)) {
$this->loadConfigurationFiles($app, $config);
}
// Finally, we will set the application's environment based on the configuration
// values that were loaded. We will pass a callback which will be used to get
// the environment in a web context where an "--env" switch is not present.
$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');
}
$items = [];
,初始化一个空数组,太简单了。。。有点侮辱智商。。。if (file_exists($cached = $app->getCachedConfigPath())) {
$items = require $cached;
$loadedFromCache = true;
}
有木有缓存文件呀,有的话,包含执行,将返回的数组赋值给 $items
,并将 $loadedFromCache
赋值为 true
。注:$app->getCachedConfigPath()
返回的缓存文件路径为 bootstrap/cache/config.php
。
$app->instance('config', $config = new Repository($items));
这个就是 Laravel 实现配置管理的核心了。将所有加载好的配置内容赋值给容器的 intances
属性,用的时候取就行了。先撇一眼加载完的图,过过 "眼瘾"。。。
[
](https://lccdn.phphub.org/uploads/images/201809/27/27709/xl3ufPiBLR.png?imageView2/2/w/1240/h/0)
这时候你肯定要问了,加载时,没有缓存文件 $items
不就是空数组啦吗?别急,接下来就是没缓存文件的处理程序
if (! isset($loadedFromCache)) {
$this->loadConfigurationFiles($app, $config);
}
这句就是没设置 $loadedFromCache
变量,就执行当前对象的 loadConfigurationFiles
方法。我的没缓存,所以就没设置 $loadedFromCache
变量,因此会执行 loadConfigurationFiles
loadConfigurationFiles
方法的具体作用,下面说。现在简单说一下它的功能:自动解析 config/
目录下的 .php
文件,支持多层目录哦,然后,将所找到的 .php
文件包含执行,取返回的数组(里面是每个 php 文件的配置内容)
$app->detectEnvironment(function () use ($config) {
return $config->get('app.env', 'production');
});
检测当前执行环境是本地环境,还是生产环境。并通过容器的 bind
方法赋值给容器的bindings
属性
[
](https://lccdn.phphub.org/uploads/images/201809/27/27709/sOH4V5wuJf.png?imageView2/2/w/1240/h/0)
这个不是重点,大家了解一下就行了。
date_default_timezone_set($config->get('app.timezone', 'UTC'));
mb_internal_encoding('UTF-8');
根据 app.timezone
设置 Laravel 执行中的时区,并设置 Laravel 执行中的字符编码("UTF-8")
下面我们重点介绍一下 loadConfigurationFiles
方法
loadConfigurationFiles
方法先贴出代码
protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
{
$files = $this->getConfigurationFiles($app);
if (! isset($files['app'])) {
throw new Exception('Unable to load the "app" configuration file.');
}
foreach ($files as $key => $path) {
$repository->set($key, require $path);
}
}
$files = $this->getConfigurationFiles($app);
这里面主要用到 了 PHP 的 SPL 基本扩展中的目录文件迭代器,循环过滤寻找需要的目录和 .php
文件,而调用这些迭代器的类是 Symfony
的 Finder
组件。
有兴趣的同学可以看这一下官网关于这个扩展的介绍 。。。点我进入
关于这个方法下面我会进入细讲
if (! isset($files['app'])) {
throw new Exception('Unable to load the "app" configuration file.');
}
如果删除了 config/app.php
文件,就会报这个异常
foreach ($files as $key => $path) {
$repository->set($key, require $path);
}
哈哈,这个就是在获取完所有配置文件路径后,正式往容器存储配置了,我们看一下 $files
变量长啥样
[
](https://lccdn.phphub.org/uploads/images/201809/27/27709/USdiuG5vtV.png?imageView2/2/w/1240/h/0)
看到没,无非就是一个数组,数组的键是 .php
的文件的名字,值是 .php
文件的绝对路径;通过包含执行,取出返回的数组(这个数组,是每个 .php
文件的具体配置内容)。之后赋值给 Repository
类的 items
属性,这样容器 intances
属性中的 config
键指向的值就会是处理好的配置内容;
为什么会这样呢,intances
属性赋值实在之前的赋值的呀。这就是 引用数据 类型的特性了:引用类型实际存储的是数据的指针,多个变量名存储不同变量值,这个变量值实际是引用数据的指针,它们都指向同一个数据源(堆中的对象源数据);一变皆变,一动皆动。。。
下面我们看一下 getConfigurationFiles
方法
getConfigurationFiles
方法老规矩,先贴代码
protected function getConfigurationFiles(Application $app)
{
$files = [];
$configPath = realpath($app->configPath());
foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
$directory = $this->getNestedDirectory($file, $configPath);
$files[$directory.basename($file->getRealPath(), '.php')] = $file->getRealPath();
}
ksort($files, SORT_NATURAL);
return $files;
}
$files = [];
,额。。。有点侮辱智商$configPath = realpath($app->configPath());
将 config/
的标准(没有 ../
)绝对路径赋值给 $configPath
foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
$directory = $this->getNestedDirectory($file, $configPath);
$files[$directory.basename($file->getRealPath(), '.php')] = $file->getRealPath();
}
这个地方就是调用了 Symfony
的 Finder
组件进行 .php
文件寻找了。
大家看这个
Finder::create()->files()->name('*.php')->in($configPath)
这个这一串,返回的是 Finder
类对象本身,但是。。。这个 Finder
类对象是一个迭代器,所以能够进行 foreach
循环,我们看一下最后这个 in
方法
public function in($dirs)
{ // $dirs: "D:\www\learn\config"
$resolvedDirs = array();
foreach ((array) $dirs as $dir) {
if (is_dir($dir)) {
$resolvedDirs[] = $this->normalizeDir($dir);
} elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
$resolvedDirs = array_merge($resolvedDirs, array_map(array($this, 'normalizeDir'), $glob));
} else {
throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
}
}
$this->dirs = array_merge($this->dirs, $resolvedDirs);
return $this;
}
乱七八糟的一堆,看的我头疼。。。其实那么多,在这里就实现一个功能:给当前对象的属性 dirs
赋值,看一图就知道了
[
](https://lccdn.phphub.org/uploads/images/201809/27/27709/WC9SQJNKHU.png?imageView2/2/w/1240/h/0)
然后呢。。。返回了 $this
,上面说过的,当前对象是一个目录文件迭代器对象,能进行 foreach
循环,其元素就是对象中 current
方法的返回值。在运行这个目录文件迭代器时,加入了一堆过滤操作,如过滤掉 ./
和 ../
这样的目录,还过滤掉了 .git
、.svn
、.hg
、_svn
这样的目录。
因为 PHP 内置的这个 SPL 迭代器基本扩展,功能很强劲,文档模模糊糊,大体知道支持目录层次循环,看 current
方法法的内容,也知道支持多层目录配置
ksort($files, SORT_NATURAL);
对 $files
数组进行自然序排序
到这里 $files
算是拿到了,呼,这么长,就为了兼容各种情况,写了这么长,看的我一个头两个大。。。
通过上面的学习我们知道了,配置文件支持多层目录,如下图,是一个多层目录配置的测试
[
](https://lccdn.phphub.org/uploads/images/201809/27/27709/FDDDFvT7Oh.png?imageView2/2/w/1240/h/0)
[
](https://lccdn.phphub.org/uploads/images/201809/27/27709/LH4AHcRMQs.png?imageView2/2/w/1240/h/0)
[
](https://lccdn.phphub.org/uploads/images/201809/27/27709/tBrKdMrrDo.png?imageView2/2/w/1240/h/0)
好了,今天的章节到这了,下一章,我们继续我们的 $bootstrappers
数组。。。
我们是一群被时空压迫的孩子。 ---- 爱因斯坦
Original url: Access
Created at: 2018-10-10 15:44:27
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论