照猫画虎 实现 min-laravel 框架系列之 config 目录文件加载
- laravel
- 2020-06-11
- 4048
- 0
config 目录文件加载
config 目录是 laravel 框架的配置文件目录。Finder 组件是由 symfony 提供的一个直观而流畅的接口来寻找文件和目录。
laravel 会将配置目录下的所有文件都读到内存变量中,多级目录会以多纬数组的形式体现,而且在获取配置变量时,遵循以下规则,ex: config(a.b.c) ,系统会尝试找 items[‘a’][‘b’][‘c’] 的值
LoadConfiguration 类
bootstrap 方法
public function bootstrap(Application $app)
{
$items = [];
// 文件缓存
if ( file_exists($cached = $app->getCachedConfigPath())) {
$items = require $cached;
$loadedFromCache = true;
}
$app->instance('config', $config = new Repository($items));
// 加载变量
if (! isset($loadedFromCache)) {
$this->loadConfigurationFiles($app, $config); // 核心函数
}
}
protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
{
// 获取 config 目录下所有 php 文件
$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);
}
}
寻找所有配置文件
laravel 使用了 finder 组件,将 path/config 目录下的所有 php 文件中的数组都读取到内存中
- 在 minlaravelframework/framework 的 composer.json 配置文件中添加依赖包
"require": {
....
"symfony/finder": "^5.0",
},
- 在 minlaravel 目录下更新, composer update
getConfigurationFiles 方法:寻找文件
protected function getConfigurationFiles(Application $app)
{
$files = [];
// 获取配置文件目录 path/config
$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;
}
getNestedDirectory 方法
将路径符号转成为点。ex: aaa/bbb/ccc ==> aaa.bbb.ccc
protected function getNestedDirectory(SplFileInfo $file, $configPath)
{
$directory = $file->getPath();
if ($nested = trim(str_replace($configPath, '', $directory), DIRECTORY_SEPARATOR)) {
$nested = str_replace(DIRECTORY_SEPARATOR, '.', $nested).'.';
}
return $nested;
}
文件寻找结果
通过对 config 目录进行遍历查找( *.php 文件 ),得到系统当前所有的配置信息
Array
(
[app] => /path/config/app.php
[custom.city] => /path/config/custom/city.php
)
Repository 类
Illuminate\Config\Repository 就是 laravel 框架加载和获取配置变量的核心类。主要包括 set 和 get 方法,
将配置变量载入内存
对 laravel 系统来说 ,app.php 的配置文件是必须要存在的,如果不存在的话,会抛出异常
Repository::set 加载变量
/**
key == value
app==Array
(
[aa] => bbb
)
custom.city==Array
(
[city] => Array
(
[0] => 北京
[1] => 上海
[2] => 深圳
)
)
*/
public function set($key, $value = null)
{
$keys = is_array($key) ? $key : [$key => $value];
foreach ($keys as $key => $value) {
Arr::set($this->items, $key, $value);
}
}
arr::set 方法
这个方法使用了函数参数的地址传递参数,理解起来稍微费点劲,
public static function set(&$array, $key, $value)
{
if (is_null($key)) {
return $array = $value;
}
// custom.city
$keys = explode('.', $key);
foreach ($keys as $i => $key) {
if (count($keys) === 1) {
break;
}
// unset 掉了,所以当 keys 数组剩余 1 个时,上边的 if 条件成立
unset($keys[$i]);
if (! isset($array[$key]) || ! is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
$array[array_shift($keys)] = $value;
return $array;
}
最后读到 Repository::item 的值
Config\Repository Object
(
[items:protected] => Array
(
[app] => Array
(
[aa] => bbb
)
[custom] => Array
(
[city] => Array
(
[city] => Array
(
[0] => 北京
[1] => 上海
[2] => 深圳
)
)
)
)
)
获取环境变量值
Repository::get 方法
public function get($key, $default = null)
{
if (is_array($key)) {
return $this->getMany($key);
}
return Arr::get($this->items, $key, $default);
}
arr::get 方法
// key = custom.city.city
public static function get($array, $key, $default = null)
{
if (! static::accessible($array)) {
return value($default);
}
if (is_null($key)) {
return $array;
}
if (static::exists($array, $key)) {
return $array[$key];
}
if (strpos($key, '.') === false) {
return $array[$key] ?? value($default);
}
foreach (explode('.', $key) as $segment) {
if (static::accessible($array) && static::exists($array, $segment)) {
$array = $array[$segment];
} else {
return value($default);
}
}
return $array;
}
helpers::config 函数
该函数就是 laravel 提供的用于获取环境变量的函数
function config($key = null, $default = null)
{
if (is_null($key)) {
return app('config');
}
if (is_array($key)) {
return app('config')->set($key);
}
return app('config')->get($key, $default); // Repository::get 方法
}