照猫画虎 实现 min-laravel 框架系列之 config 目录文件加载
- laravel
- 2020-06-11
- 371
- 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 == valueapp==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.citypublic 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 方法}