|null */ private static ?array $store = null; /** * 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 */ public static function get(string $key, mixed $default = null): mixed { // 1) Environment lookup (supports dot.notation by converting to UPPER_SNAKE) $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]; } // 2) Config files (lazy load once) self::ensureLoaded(); if (self::$store) { $fromStore = self::getFromStore($key); if ($fromStore !== null) { return $fromStore; } } // 3) Default return $default; } 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; } }