照猫画虎 实现 min-laravel 框架系列之 config 目录文件加载

php   laravel  

config 目录文件加载

config 目录是 laravel 框架的配置文件目录。Finder 组件是由 symfony 提供的一个直观而流畅的接口来寻找文件和目录。

laravel 会将配置目录下的所有文件都读到内存变量中,多级目录会以多纬数组的形式体现,而且在获取配置变量时,遵循以下规则,ex: config(a.b.c) ,系统会尝试找 items[‘a’][‘b’][‘c’] 的值

LoadConfiguration 类

bootstrap 方法

  1. public function bootstrap(Application $app)
  2. {
  3. $items = [];
  4. // 文件缓存
  5. if ( file_exists($cached = $app->getCachedConfigPath())) {
  6. $items = require $cached;
  7. $loadedFromCache = true;
  8. }
  9. $app->instance('config', $config = new Repository($items));
  10. // 加载变量
  11. if (! isset($loadedFromCache)) {
  12. $this->loadConfigurationFiles($app, $config); // 核心函数
  13. }
  14. }
  15. protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
  16. {
  17. // 获取 config 目录下所有 php 文件
  18. $files = $this->getConfigurationFiles($app);
  19. if ( ! isset($files['app']) ) {
  20. throw new Exception('Unable to load the "app" configuration file.');
  21. }
  22. // 对文件进行遍历,将数组变量载入内存
  23. foreach ($files as $key => $path) {
  24. $repository->set($key, require $path);
  25. }
  26. }

寻找所有配置文件

laravel 使用了 finder 组件,将 path/config 目录下的所有 php 文件中的数组都读取到内存中

  • 在 minlaravelframework/framework 的 composer.json 配置文件中添加依赖包
  1. "require": {
  2. ....
  3. "symfony/finder": "^5.0",
  4. },
  • 在 minlaravel 目录下更新, composer update

getConfigurationFiles 方法:寻找文件

  1. protected function getConfigurationFiles(Application $app)
  2. {
  3. $files = [];
  4. // 获取配置文件目录 path/config
  5. $configPath = realpath($app->configPath());
  6. // 遍历目录
  7. foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
  8. $directory = $this->getNestedDirectory($file, $configPath);
  9. $files[$directory.basename($file->getRealPath(), '.php')] = $file->getRealPath();
  10. }
  11. ksort($files, SORT_NATURAL);
  12. return $files;
  13. }

getNestedDirectory 方法

将路径符号转成为点。ex: aaa/bbb/ccc ==> aaa.bbb.ccc

  1. protected function getNestedDirectory(SplFileInfo $file, $configPath)
  2. {
  3. $directory = $file->getPath();
  4. if ($nested = trim(str_replace($configPath, '', $directory), DIRECTORY_SEPARATOR)) {
  5. $nested = str_replace(DIRECTORY_SEPARATOR, '.', $nested).'.';
  6. }
  7. return $nested;
  8. }

文件寻找结果

通过对 config 目录进行遍历查找( *.php 文件 ),得到系统当前所有的配置信息

  1. Array
  2. (
  3. [app] => /path/config/app.php
  4. [custom.city] => /path/config/custom/city.php
  5. )

Repository 类

Illuminate\Config\Repository 就是 laravel 框架加载和获取配置变量的核心类。主要包括 set 和 get 方法,

将配置变量载入内存

对 laravel 系统来说 ,app.php 的配置文件是必须要存在的,如果不存在的话,会抛出异常

Repository::set 加载变量

  1. /**
  2. key == value
  3. app==Array
  4. (
  5. [aa] => bbb
  6. )
  7. custom.city==Array
  8. (
  9. [city] => Array
  10. (
  11. [0] => 北京
  12. [1] => 上海
  13. [2] => 深圳
  14. )
  15. )
  16. */
  17. public function set($key, $value = null)
  18. {
  19. $keys = is_array($key) ? $key : [$key => $value];
  20. foreach ($keys as $key => $value) {
  21. Arr::set($this->items, $key, $value);
  22. }
  23. }

arr::set 方法

这个方法使用了函数参数的地址传递参数,理解起来稍微费点劲,

  1. public static function set(&$array, $key, $value)
  2. {
  3. if (is_null($key)) {
  4. return $array = $value;
  5. }
  6. // custom.city
  7. $keys = explode('.', $key);
  8. foreach ($keys as $i => $key) {
  9. if (count($keys) === 1) {
  10. break;
  11. }
  12. // unset 掉了,所以当 keys 数组剩余 1 个时,上边的 if 条件成立
  13. unset($keys[$i]);
  14. if (! isset($array[$key]) || ! is_array($array[$key])) {
  15. $array[$key] = [];
  16. }
  17. $array = &$array[$key];
  18. }
  19. $array[array_shift($keys)] = $value;
  20. return $array;
  21. }

最后读到 Repository::item 的值

  1. Config\Repository Object
  2. (
  3. [items:protected] => Array
  4. (
  5. [app] => Array
  6. (
  7. [aa] => bbb
  8. )
  9. [custom] => Array
  10. (
  11. [city] => Array
  12. (
  13. [city] => Array
  14. (
  15. [0] => 北京
  16. [1] => 上海
  17. [2] => 深圳
  18. )
  19. )
  20. )
  21. )
  22. )

获取环境变量值

Repository::get 方法

  1. public function get($key, $default = null)
  2. {
  3. if (is_array($key)) {
  4. return $this->getMany($key);
  5. }
  6. return Arr::get($this->items, $key, $default);
  7. }

arr::get 方法

  1. // key = custom.city.city
  2. public static function get($array, $key, $default = null)
  3. {
  4. if (! static::accessible($array)) {
  5. return value($default);
  6. }
  7. if (is_null($key)) {
  8. return $array;
  9. }
  10. if (static::exists($array, $key)) {
  11. return $array[$key];
  12. }
  13. if (strpos($key, '.') === false) {
  14. return $array[$key] ?? value($default);
  15. }
  16. foreach (explode('.', $key) as $segment) {
  17. if (static::accessible($array) && static::exists($array, $segment)) {
  18. $array = $array[$segment];
  19. } else {
  20. return value($default);
  21. }
  22. }
  23. return $array;
  24. }

helpers::config 函数

该函数就是 laravel 提供的用于获取环境变量的函数

  1. function config($key = null, $default = null)
  2. {
  3. if (is_null($key)) {
  4. return app('config');
  5. }
  6. if (is_array($key)) {
  7. return app('config')->set($key);
  8. }
  9. return app('config')->get($key, $default); // Repository::get 方法
  10. }


评论 0

发表评论

Top