当前位置: 首页 > news >正文

PHP配置中心与动态配置管理

PHP配置中心与动态配置管理

配置管理是应用运维的重要环节。配置中心可以让配置动态变更,不需要重启应用。今天说说PHP中的配置管理方案。

传统的配置文件方式简单直接,但修改配置需要重新部署。

```php
// 文件配置
class FileConfig
{
private array $configs = [];
private string $configDir;
private array $loaded = [];

public function __construct(string $configDir = __DIR__ . '/config')
{
$this->configDir = rtrim($configDir, '/');
}

public function load(): void
{
$files = glob($this->configDir . '/*.php');
foreach ($files as $file) {
$key = basename($file, '.php');
$this->configs[$key] = require $file;
$this->loaded[] = $key;
}
}

public function get(string $key, mixed $default = null): mixed
{
$keys = explode('.', $key);
$value = $this->configs;

foreach ($keys as $segment) {
if (!is_array($value) || !array_key_exists($segment, $value)) {
return $default;
}
$value = $value[$segment];
}

return $value;
}

public function set(string $key, mixed $value): void
{
$keys = explode('.', $key);
$config = &$this->configs;

foreach ($keys as $segment) {
if (!isset($config[$segment])) {
$config[$segment] = [];
}
$config = &$config[$segment];
}

$config = $value;
}

public function all(): array
{
return $this->configs;
}

public function reload(): void
{
$this->configs = [];
$this->load();
}
}
?>

// config/app.php
return [
'name' => 'MyApp',
'debug' => false,
'env' => 'production',
'timezone' => 'Asia/Shanghai',
];
?>

// config/database.php
return [
'default' => 'mysql',
'connections' => [
'mysql' => [
'host' => 'localhost',
'port' => 3306,
'database' => 'test',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
],
'redis' => [
'host' => 'localhost',
'port' => 6379,
'database' => 0,
],
],
];
?>

$config = new FileConfig();
$config->load();
echo "应用名称: " . $config->get('app.name') . "\n";
echo "数据库主机: " . $config->get('database.connections.mysql.host') . "\n";
?>
```

基于Redis的动态配置中心:

```php
class RedisConfigCenter
{
private Redis $redis;
private string $prefix = 'config:';
private array $localCache = [];
private int $cacheTtl = 60;

public function __construct(Redis $redis)
{
$this->redis = $redis;
}

public function get(string $key, mixed $default = null): mixed
{
$cacheKey = "{$this->prefix}{$key}";

// 从本地缓存获取
if (isset($this->localCache[$cacheKey])) {
$cached = $this->localCache[$cacheKey];
if ($cached['expires'] > time()) {
return $cached['value'];
}
}

// 从Redis获取
$value = $this->redis->get($cacheKey);
if ($value === false) {
return $default;
}

$decoded = json_decode($value, true);
$this->localCache[$cacheKey] = [
'value' => $decoded,
'expires' => time() + $this->cacheTtl,
];

return $decoded;
}

public function set(string $key, mixed $value): void
{
$cacheKey = "{$this->prefix}{$key}";
$this->redis->set($cacheKey, json_encode($value));
unset($this->localCache[$cacheKey]);

// 发布配置变更通知
$this->redis->publish('config_changes', json_encode([
'key' => $key,
'time' => time(),
]));
}

public function delete(string $key): void
{
$cacheKey = "{$this->prefix}{$key}";
$this->redis->del($cacheKey);
unset($this->localCache[$cacheKey]);
}

public function getMultiple(array $keys): array
{
$results = [];
foreach ($keys as $key) {
$results[$key] = $this->get($key);
}
return $results;
}

public function setMultiple(array $configs): void
{
foreach ($configs as $key => $value) {
$this->set($key, $value);
}
}

public function getAllWithPrefix(string $prefix = ''): array
{
$pattern = "{$this->prefix}{$prefix}*";
$keys = $this->redis->keys($pattern);
$result = [];

foreach ($keys as $key) {
$configKey = str_replace($this->prefix, '', $key);
$result[$configKey] = json_decode($this->redis->get($key), true);
}

return $result;
}

public function watchChanges(callable $callback): void
{
$this->redis->subscribe(['config_changes'], function ($redis, $channel, $message) use ($callback) {
$data = json_decode($message, true);
$callback($data['key'], $data['time']);
});
}
}

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$configCenter = new RedisConfigCenter($redis);

$configCenter->set('app.debug', true);
$configCenter->set('app.name', 'MyApp');
$configCenter->set('database.host', 'localhost');
$configCenter->set('database.port', 3306);
$configCenter->set('cache.ttl', 3600);
$configCenter->set('features.new_ui', false);

echo "调试模式: " . ($configCenter->get('app.debug') ? '开启' : '关闭') . "\n";
echo "数据库主机: " . $configCenter->get('database.host') . "\n";
echo "缓存TTL: " . $configCenter->get('cache.ttl') . "\n";
echo "默认值: " . $configCenter->get('nonexistent', 'default') . "\n";
?>
```

环境配置的自动切换:

```php
class EnvironmentConfig
{
private array $configs = [];
private string $env;

public function __construct()
{
$this->env = $this->detectEnvironment();
$this->loadConfigs();
}

private function detectEnvironment(): string
{
$env = getenv('APP_ENV');
if ($env) return $env;

if (file_exists('.env.local')) return 'local';
if (file_exists('.env.dev'])) return 'development';
if (file_exists('.env.staging')) return 'staging';

return 'production';
}

private function loadConfigs(): void
{
$envFile = ".env.{$this->env}";
$baseFile = '.env';

$files = [$baseFile, $envFile];
foreach ($files as $file) {
if (file_exists($file)) {
$this->parseEnvFile($file);
}
}
}

private function parseEnvFile(string $path): void
{
$lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

foreach ($lines as $line) {
$line = trim($line);
if ($line === '' || str_starts_with($line, '#')) continue;

if (str_contains($line, '=')) {
[$key, $value] = explode('=', $line, 2);
$key = trim($key);
$value = trim($value);

// 处理引号
if (str_starts_with($value, '"') && str_ends_with($value, '"')) {
$value = substr($value, 1, -1);
}

// 类型转换
$value = match (strtolower($value)) {
'true' => true,
'false' => false,
'null' => null,
default => $value,
};

$this->configs[$key] = $value;
putenv("{$key}=" . (is_bool($value) ? ($value ? 'true' : 'false') : (string)$value));
}
}
}

public function get(string $key, mixed $default = null): mixed
{
return $this->configs[$key] ?? getenv($key) ?: $default;
}

public function getEnvironment(): string
{
return $this->env;
}

public function isLocal(): bool
{
return $this->env === 'local';
}

public function isProduction(): bool
{
return $this->env === 'production';
}

public function isDevelopment(): bool
{
return $this->env === 'development';
}

public function all(): array
{
return $this->configs;
}
}

$config = new EnvironmentConfig();
echo "当前环境: " . $config->getEnvironment() . "\n";
echo "是否生产环境: " . ($config->isProduction() ? '是' : '否') . "\n";
?>
```

配置是应用的基石。好的配置管理方案可以让运维更轻松,开发更高效。文件配置简单明了,适合中小项目。配置中心灵活强大,适合分布式系统。环境配置通过.env文件自动切换,是开发环境的标配。

http://www.rkmt.cn/news/1458959.html

相关文章:

  • 25个Adobe Illustrator脚本:终极设计自动化解决方案
  • 3种高性能架构方案对比:Poppler-Windows的云原生部署终极指南
  • 戴尔G15散热控制神器:TCC-G15开源替代方案完全指南
  • 从UE4到Unity:技术美术面试官最爱问的Shader与渲染管线10大高频题(附避坑指南)
  • 从排队到金融风控:用Python实战模拟泊松过程,理解事件流的合成与分解
  • STM32 Bootloader跳转App总进HardFault?一个PSP和MSP的堆栈陷阱
  • ROS开发专栏---基于图像视觉的目标追踪实验--适配Ubuntu 22.04
  • 智能资源嗅探革命:5步实现浏览器媒体资源自动化管理
  • Cursor与Grok 4真实能力边界:AST驱动开发提效与本地化推理实践
  • 【2024音频AI整合生死线】:为什么你的ASR准确率骤降37%?——基于17个真实产线故障的日志溯源报告
  • 计算机毕业设计之基于python的抖音舆情可视化系统
  • 实战演练,基于快马AI生成游戏背包系统,掌握ccswitch在复杂UI中的核心应用
  • macOS终端生产力方案:iTerm2+zsh+Powerlevel10k配置指南
  • Armbian vs Arch Linux ARM:在全志A13平板上部署Linux,我最终选择了它(附完整配置流程)
  • Postman调试指南:如何用@PathVariable注解快速构建和测试RESTful API接口
  • 2026 苏州全域厂房修缮优选榜单|外墙出新 / 彩钢防腐 / 屋面防水 / 环氧地坪 3 家正规工装企业实测 + 本地化避坑全指南 - 本地便民网
  • 从微信‘偷师’到APK打包:一次搞定腾讯TBS X5内核的离线集成与架构适配
  • 如何在3分钟内让Blender变身专业3D打印工具:终极3MF格式插件指南
  • XUnity.AutoTranslator终极指南:开启游戏无障碍翻译新时代
  • 别再被0.1+0.2≠0.3搞懵了!从IEEE 754标准出发,手把手带你理解浮点数的‘规格化’与‘非规格化’
  • 2026 江苏南通全域商铺 / 办公室工装优选榜单|门面整装、商场改造、写字楼翻新 3 家正规装修企业实测测评 + 本地化避坑全攻略 - 本地便民网
  • 工业智能一体机和商用一体机差价在哪?拆开看内部
  • 评价超高!这家固定式集装箱翻转机直销厂家究竟有何过人之处?
  • 金融大模型社招|RAG 搜索 / 大模型算法 / 大模型安全
  • 别再对着型号发愁了!手把手教你解读国产DJ接插件命名规则(附AMP对照表)
  • DeepSeek-V4深度解析:长记忆与强Agent协同架构
  • 零基础福音:在快马平台跟着ai生成的互动指南完成python首次安装
  • 让 Agent 具备业务常识的三种策略
  • 学生编程入门最佳AI编程工具最新推荐:8款实测工具搞定作业、课程项目与竞赛
  • MyBatis-Plus更新数据实战:从单字段修改到复杂条件更新的完整配置流程