A Configuration Manager allows you to load configuration settings from various sources, such as files, environment variables, or databases. This tutorial will guide you through implementing a simple yet effective Configuration Manager in PHP, focusing on best practices and real-world examples.

Step 1: Define the Configuration Structure

First, we need to define how our configuration will be structured. A common approach is to use an associative array where keys represent configuration names and values hold the corresponding settings.

class ConfigManager {
    private $config = [];

    public function load(array $configData) {
        $this->config = $configData;
    }

    public function get($key, $default = null) {
        return $this->config[$key] ?? $default;
    }
}

Step 2: Loading Configuration from Files

We can extend our ConfigManager class to load configuration settings from a JSON file. This is a common practice, as JSON provides a human-readable format that is easy to edit.

class ConfigManager {
    private $config = [];

    public function loadFromFile($filePath) {
        if (!file_exists($filePath)) {
            throw new \Exception("Configuration file not found: $filePath");
        }

        $json = file_get_contents($filePath);
        $this->config = json_decode($json, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new \Exception("Error parsing JSON: " . json_last_error_msg());
        }
    }

    public function get($key, $default = null) {
        return $this->config[$key] ?? $default;
    }
}

Example JSON Configuration File

Create a file named config.json with the following content:

{
    "database": {
        "host": "localhost",
        "username": "root",
        "password": "secret",
        "dbname": "test_db"
    },
    "app": {
        "debug": true,
        "log_level": "info"
    }
}

Usage

Now, we can use our ConfigManager to load and access configuration settings.

$configManager = new ConfigManager();
$configManager->loadFromFile('config.json');

$dbHost = $configManager->get('database.host');
$debugMode = $configManager->get('app.debug');

echo "Database Host: $dbHost\n";
echo "Debug Mode: " . ($debugMode ? 'Enabled' : 'Disabled') . "\n";

Step 3: Adding Environment Variable Support

In addition to loading configuration from files, it's often useful to allow overriding settings using environment variables. This can be particularly helpful in production environments.

class ConfigManager {
    private $config = [];

    public function loadFromFile($filePath) {
        // Previous implementation...
    }

    public function loadFromEnv() {
        foreach ($_ENV as $key => $value) {
            // Convert environment variable names to config keys
            $configKey = strtolower(str_replace('_', '.', $key));
            $this->config[$configKey] = $value;
        }
    }

    public function get($key, $default = null) {
        return $this->config[$key] ?? $default;
    }
}

Usage with Environment Variables

Set environment variables in your server or local environment:

export DATABASE_HOST='127.0.0.1'
export APP_DEBUG='false'

Now, we can load both the JSON configuration and the environment variables:

$configManager = new ConfigManager();
$configManager->loadFromFile('config.json');
$configManager->loadFromEnv();

$dbHost = $configManager->get('database.host');
$debugMode = $configManager->get('app.debug');

echo "Database Host: $dbHost\n";
echo "Debug Mode: " . ($debugMode ? 'Enabled' : 'Disabled') . "\n";

Step 4: Merging Configuration Sources

To provide a more robust configuration management system, we can implement a method to merge configurations from multiple sources. This allows for defaults to be overridden by environment variables or other sources.

class ConfigManager {
    private $config = [];

    public function loadFromFile($filePath) {
        // Previous implementation...
    }

    public function loadFromEnv() {
        // Previous implementation...
    }

    public function merge(array $newConfig) {
        $this->config = array_merge($this->config, $newConfig);
    }

    public function get($key, $default = null) {
        return $this->config[$key] ?? $default;
    }
}

Merging Example

$configManager = new ConfigManager();
$configManager->loadFromFile('config.json');
$configManager->loadFromEnv();

// Override specific settings
$configManager->merge([
    'database.host' => '192.168.1.1',
]);

$dbHost = $configManager->get('database.host');
echo "Database Host: $dbHost\n"; // Outputs: Database Host: 192.168.1.1

Conclusion

Implementing a custom PHP Configuration Manager enhances your application's flexibility and maintainability. By centralizing configuration management, you can easily adapt to different environments and requirements. The example provided demonstrates how to load configuration from files, environment variables, and merge settings effectively.

Learn more with useful resources