Framework/src/Support/Config.php

94 lines
2.7 KiB
PHP
Raw Normal View History

2025-12-14 23:10:01 +00:00
<?php
declare(strict_types=1);
namespace Phred\Support;
final class Config
{
2025-12-15 02:09:06 +00:00
/** @var array<string,mixed>|null */
private static ?array $store = null;
2025-12-14 23:10:01 +00:00
/**
2025-12-15 02:09:06 +00:00
* Get configuration value with precedence:
* 1) Environment variables (UPPER_CASE or dot.notation translated)
* 2) Loaded config files from config/*.php, accessible via dot.notation (e.g., app.env)
* 3) Provided $default
2025-12-14 23:10:01 +00:00
*/
public static function get(string $key, mixed $default = null): mixed
{
2025-12-15 02:09:06 +00:00
// 1) Environment lookup (supports dot.notation by converting to UPPER_SNAKE)
2025-12-14 23:10:01 +00:00
$envKey = strtoupper(str_replace('.', '_', $key));
$value = getenv($envKey);
if ($value !== false) {
return $value;
}
if (isset($_SERVER[$envKey])) {
return $_SERVER[$envKey];
}
if (isset($_ENV[$envKey])) {
return $_ENV[$envKey];
}
2025-12-15 02:09:06 +00:00
// 2) Config files (lazy load once)
self::ensureLoaded();
if (self::$store) {
$fromStore = self::getFromStore($key);
if ($fromStore !== null) {
return $fromStore;
}
}
// 3) Default
2025-12-14 23:10:01 +00:00
return $default;
}
2025-12-15 02:09:06 +00:00
private static function ensureLoaded(): void
{
if (self::$store !== null) {
return;
}
self::$store = [];
$root = getcwd();
$configDir = $root . DIRECTORY_SEPARATOR . 'config';
if (!is_dir($configDir)) {
return; // no config directory; keep empty store
}
foreach (glob($configDir . '/*.php') ?: [] as $file) {
$key = basename($file, '.php');
try {
$data = require $file;
if (is_array($data)) {
self::$store[$key] = $data;
}
} catch (\Throwable) {
// ignore malformed config files to avoid breaking runtime
}
}
}
private static function getFromStore(string $key): mixed
{
// dot.notation: first segment is file key, remaining traverse array
if (str_contains($key, '.')) {
$parts = explode('.', $key);
$rootKey = array_shift($parts);
if ($rootKey === null || !isset(self::$store[$rootKey])) {
return null;
}
$cursor = self::$store[$rootKey];
foreach ($parts as $p) {
if (is_array($cursor) && array_key_exists($p, $cursor)) {
$cursor = $cursor[$p];
} else {
return null;
}
}
return $cursor;
}
// non-dotted: try exact file key
return self::$store[$key] ?? null;
}
2025-12-14 23:10:01 +00:00
}