Don’t Let Eagerly Loaded Config Crash Code Paths That Don’t Use It

📖 2 minutes read

Here’s a subtle way constructors can blow up in production: eagerly loading optional configuration that the current execution path doesn’t need.

Imagine you have a class that manages API credentials for both live and sandbox modes:

class GatewayCredentials
{
    private string $apiKey;
    private ?string $sandboxApiKey;
    private string $secretKey;
    private ?string $sandboxSecretKey;

    public function __construct(array $config, array $sandboxConfig)
    {
        $this->apiKey = $config['api_key'];
        $this->sandboxApiKey = $sandboxConfig['api_key'];     // 💥 crashes here
        $this->secretKey = $config['secret_key'];
        $this->sandboxSecretKey = $sandboxConfig['secret_key']; // 💥 or here
    }
}

The constructor always loads both live and sandbox credentials, even when the app is running in production mode and will never touch the sandbox values. If the sandbox config is incomplete (missing keys, empty array, or null), PHP 8 promotes undefined array key access from a notice to a warning — and frameworks like Laravel convert that warning into an ErrorException — and your production checkout page crashes because of test data that isn’t even needed.

The fix: defer with null coalescing

class GatewayCredentials
{
    private string $apiKey;
    private ?string $sandboxApiKey;
    private string $secretKey;
    private ?string $sandboxSecretKey;
    private bool $sandboxMode;

    public function __construct(array $config, array $sandboxConfig, bool $sandboxMode = false)
    {
        $this->sandboxMode = $sandboxMode;

        // Live credentials are always required
        $this->apiKey = $config['api_key'];
        $this->secretKey = $config['secret_key'];

        // Sandbox credentials are optional — don't crash if missing
        $this->sandboxApiKey = $sandboxConfig['api_key'] ?? null;
        $this->sandboxSecretKey = $sandboxConfig['secret_key'] ?? null;
    }

    public function getApiKey(): string
    {
        return $this->sandboxMode
            ? ($this->sandboxApiKey ?? throw new \RuntimeException('Sandbox API key not configured'))
            : $this->apiKey;
    }
}

The key insight: use ?? for optional config in the constructor, but fail loudly at the point of use if the value is actually needed. This way:

  • Production never crashes due to missing test config
  • Sandbox mode still fails fast with a clear error message
  • The constructor stays defensive without hiding real problems

This pattern applies anywhere you have multi-environment or multi-mode configuration. Don’t let eagerly loaded optional data crash the paths that don’t use it.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *