Null Coalescing for Safe Configuration Access

📖 2 minutes read

Configuration arrays—whether from databases, API responses, or config files—can be incomplete or inconsistent. Directly accessing keys without checking for their existence causes Undefined array key errors in PHP 8+.

The Problem

This constructor assumes all configuration keys exist:

class ServiceCredentials
{
    private string $apiKey;
    private string $testApiKey;
    private string $secretToken;
    private string $testSecretToken;

    public function __construct(array $config, bool $isTest)
    {
        $this->apiKey = $config['api_key'];
        $this->testApiKey = $config['test']['api_key'];  // ❌ Crashes if test.api_key missing
        
        $this->secretToken = $config['secret_token'];
        $this->testSecretToken = $config['test']['secret_token'];  // ❌ Crashes if test.secret_token missing
    }
}

When $config['test'] is incomplete (missing api_key or secret_token), PHP 8 throws ErrorException: Undefined array key and your app crashes.

The Solution

Use null coalescing (??) to provide fallback values:

class ServiceCredentials
{
    private ?string $apiKey;
    private ?string $testApiKey;
    private ?string $secretToken;
    private ?string $testSecretToken;

    public function __construct(array $config, bool $isTest)
    {
        $this->apiKey = $config['api_key'] ?? null;
        $this->testApiKey = $config['test']['api_key'] ?? null;  // ✅ Graceful
        
        $this->secretToken = $config['secret_token'] ?? null;
        $this->testSecretToken = $config['test']['secret_token'] ?? null;  // ✅ Graceful
    }
    
    public function getApiKey(): string
    {
        if ($this->isTest && $this->testApiKey !== null) {
            return $this->testApiKey;
        }
        
        return $this->apiKey ?? throw new \RuntimeException('API key not configured');
    }
}

Why This Works

  • Defensive coding — Configuration can be incomplete, user-managed, or legacy
  • Graceful degradation — System doesn’t crash on initialization; fails at the point where the value is actually needed with better context
  • Backwards compatible — Doesn’t break existing working configurations
  • Type-safe — Nullable types (?string) signal that values might be absent

When to Use This

  • Database-stored configuration (user-editable, schema evolves)
  • API response deserialization (external APIs change)
  • Multi-environment credentials (test/staging/production)
  • Optional feature flags or settings

Rule of thumb: If a config key might be missing in production without it being a fatal error, use ?? + nullable types. If it’s always required, let it crash early with a clear error.

Discovered while debugging a production error where test credentials were incomplete in a third-party service integration. The fix: 4 lines changed, zero data migrations required.

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 *