diff --git a/src/ZM/Config/RefactoredConfig.php b/src/ZM/Config/RefactoredConfig.php new file mode 100644 index 00000000..719842ab --- /dev/null +++ b/src/ZM/Config/RefactoredConfig.php @@ -0,0 +1,207 @@ +config_paths = $config_paths; + $this->environment = $environment; + $this->holder = new Config([]); + $this->loadFiles(); + } + + /** + * 获取内部配置容器 + */ + public function getHolder(): Config + { + return $this->holder; + } + + /** + * 获取配置项 + * + * @param string $key 配置项名称,可使用.访问数组 + * @param mixed $default 默认值 + * + * @return null|array|mixed + */ + public function get(string $key, $default = null) + { + return $this->holder->get($key, $default); + } + + /** + * 设置配置项 + * 仅在本次运行期间生效,不会保存到配置文件中哦 + * + * @param string $key 配置项名称,可使用.访问数组 + * @param mixed $value 要写入的值,传入 null 会进行删除 + */ + public function set(string $key, $value) + { + $this->holder->set($key, $value); + } + + /** + * 合并传入的配置数组至指定的配置项 + * + * @param string $key 目标配置项,必须为数组 + * @param array $config 要合并的配置数组 + */ + public function merge(string $key, array $config) + { + $original = $this->get($key, []); + $this->set($key, array_merge($original, $config)); + } + + /** + * 加载配置文件 + * + * @throws ConfigException + */ + public function loadFiles() + { + foreach ($this->config_paths as $config_path) { + $files = scandir($config_path); + foreach ($files as $file) { + if (!in_array(pathinfo($file, PATHINFO_EXTENSION), self::ALLOWED_FILE_EXTENSIONS)) { + continue; + } + $file_path = $config_path . '/' . $file; + if (is_dir($file_path)) { + // TODO: 支持子目录(待定) + continue; + } + $this->loadConfigFromPath($file_path); + } + } + } + + /** + * 重载配置文件 + * 运行期间新增的配置文件不会被加载哟~ + * + * @throws ConfigException + */ + public function reload() + { + $this->holder = new Config([]); + $this->loadFiles(); + } + + /** + * 从传入的路径加载配置文件 + * + * @param string $path 配置文件路径 + * + * @throws ConfigException 传入的配置文件不支持 + */ + private function loadConfigFromPath(string $path) + { + if (in_array($path, $this->loaded_files)) { + return; + } + $this->loaded_files[] = $path; + + // 判断文件格式是否支持 + $info = pathinfo($path); + $name = $info['filename']; + $ext = $info['extension']; + if (!in_array($ext, self::ALLOWED_FILE_EXTENSIONS)) { + throw new ConfigException('E00079', "不支持的配置文件格式:{$ext}"); + } + + // 判断是否应该加载 + if (!$this->shouldLoadFile($name)) { + return; + } + + // 读取并解析配置 + $content = file_get_contents($path); + $config = []; + switch ($ext) { + case 'php': + $config = require $path; + break; + case 'json': + $config = json_decode($content, true); + break; + case 'yaml': + case 'yml': + // TODO: 实现yaml解析 + break; + case 'toml': + // TODO: 实现toml解析 + break; + default: + throw new ConfigException('E00079', "不支持的配置文件格式:{$ext}"); + } + + // 加入配置 + $this->merge($name, $config); + } + + /** + * 判断是否应该加载配置文件 + * + * @param string $name 文件名 + */ + private function shouldLoadFile(string $name): bool + { + // 传入此处的 name 参数有两种可能的格式: + // 1. 纯文件名:如 test + // 2. 文件名.环境:如 test.development + // 对于第一种格式,在任何情况下均应该加载 + // 对于第二种格式,只有当环境与当前环境相同时才加载 + // 至于其他的格式,则为未定义行为 + if (strpos($name, '.') === false) { + return true; + } + $name_and_env = explode('.', $name); + if (count($name_and_env) !== 2) { + return false; + } + return $name_and_env[1] === $this->environment; + } +}