Skip to content

PHP Tutorial Practical PHP Development

Configuration Management

Lesson 315 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

A real application has many settings: the database host, the site name, debug mode, mail server, cache time. Some are secret. Some differ between your laptop and the live server. Configuration management is the habit of keeping them out of your logic and in one organised place.

Code vs configuration

CodeConfiguration
Same everywhereDifferent per environment
Reviewed and committedOften secret, so not committed
calculateTax()TAX_RATE, DB_PASSWORD

If changing a value means editing code in ten files, it should have been configuration.

Environments

Most projects run in at least three:

EnvironmentPurposeTypical settings
localYour computerDebug on, errors shown, test database
stagingA copy of the live site for testingDebug off, real-like data
productionThe live siteDebug off, errors logged, strong secrets

The same code runs in all three. Only the configuration changes.

A config file that returns an array

config/app.php
PHP
<?php

return [
    "name" => "Code Corner",
    "debug" => false,
    "timezone" => "Asia/Kolkata",
    "per_page" => 10,
];

A small Config class

index.php
PHP
<?php
final class Config
{
    public function __construct(private array $items) {}

    public function get(string $key, mixed $default = null): mixed
    {
        $value = $this->items;

        foreach (explode(".", $key) as $part) {
            if (!is_array($value) || !array_key_exists($part, $value)) {
                return $default;
            }

            $value = $value[$part];
        }

        return $value;
    }
}

$config = new Config([
    "app" => ["name" => "Code Corner", "debug" => false],
    "db" => ["host" => "127.0.0.1", "port" => 3306],
]);

echo $config->get("app.name") . "\n";
echo $config->get("db.port") . "\n";
echo $config->get("mail.host", "not configured");
Output
OUTPUT
Code Corner
3306
not configured

The class reads nested values with a dotted key, and returns a default when a setting is missing.

Pass configuration in, do not reach out for it

index.php
PHP
<?php
final class Paginator
{
    public function __construct(private int $perPage) {}

    public function pages(int $total): int
    {
        return (int) ceil($total / $this->perPage);
    }
}

$perPage = 10;   // in the real app: $config->get("app.per_page")

echo (new Paginator($perPage))->pages(47);
Output
OUTPUT
5

The Paginator knows nothing about where the number came from. It is easy to test, and easy to reuse. This is dependency injection applied to settings.

Rules

  1. One place for each setting.
  2. Defaults that are safe (debug off, not on).
  3. Secrets from the environment, never committed (Environment Variables).
  4. Validate required settings at startup, and fail with a clear message if one is missing.
  5. Do not read $_ENV, getenv() or config files all over the code. Read them once, in one place, and pass values down.

Fail early on missing settings

index.php
PHP
<?php
function requireSetting(array $settings, string $key): string
{
    $value = $settings[$key] ?? "";

    if ($value === "") {
        throw new RuntimeException("Missing required setting: $key");
    }

    return $value;
}

try {
    requireSetting(["DB_HOST" => "127.0.0.1"], "DB_NAME");
} catch (RuntimeException $e) {
    echo $e->getMessage();
}
Output
OUTPUT
Missing required setting: DB_NAME

A clear error at startup is far better than a strange failure in the middle of a request.

info
Why this matters in WordPress and Laravel
WordPress keeps settings in wp-config.php constants and the wp_options table. Laravel keeps files in config/ that read values with env() from a .env file. Both separate code from settings, the same way.