Phase 5 · Professional ApplicationsModule 30~42 min read

Configuration, Environments & Packages

Bootstrap applications with environment-aware configuration, protected secrets, and disciplined dependency management.

What you'll learn

Make the same artifact run predictably in development, test, staging, and production. Configuration enters at startup, secrets remain outside source, and Composer scripts standardize how the team installs and checks the application.

By the end of this lesson, you'll be able to:

  • Separate code, configuration, and secrets
  • Validate environment settings at startup
  • Create repeatable Composer workflows

Core mental model

Professional PHP is less about memorizing APIs and more about choosing a clear boundary for each responsibility. Use this table as a decision guide while reading the examples.

ConceptWhat it protectsDecision rule
Environment variableDeploy-specific inputUse for values that change between deployments.
BootstrapSingle construction pathLoad, validate, and freeze config before handling work.
Dependency constraintCompatible upgrade rangeUse the narrowest range supported by tests.

Professional workflow

Build the feature in small, verifiable steps. Each step leaves the system in a state you can test.

  1. Describe the application bootstrap boundary: its inputs, outputs, invariants, and expected failures.
  2. Implement the smallest happy path behind an explicit contract.
  3. Add validation and translate low-level failures into language the caller understands.
  4. Exercise the boundary with realistic data, then inspect output, logs, and resource cleanup.
  5. Refactor only after behavior is protected by a repeatable check.

Make the boundary visible

Name inputs, outputs, side effects, and failure cases before adding framework or infrastructure code. That habit keeps advanced PHP understandable as the application grows.

Guided code lab

Fail fast on missing configuration

A typed configuration object prevents environment reads from spreading through domain code.

Config.php
<?php
final readonly class Config
{
    public function __construct(
        public string $environment,
        public string $databaseDsn,
        public bool $debug,
    ) {}

    public static function fromEnvironment(): self
    {
        $dsn = $_ENV['DB_DSN'] ?? throw new RuntimeException('DB_DSN is required');
        $env = $_ENV['APP_ENV'] ?? 'production';
        return new self($env, $dsn, filter_var($_ENV['APP_DEBUG'] ?? false, FILTER_VALIDATE_BOOL));
    }
}

Standardize team commands

Composer scripts make local and CI quality checks use the same entry points.

composer.json
{
  "require": { "php": "^8.3", "vlucas/phpdotenv": "^5.6" },
  "require-dev": { "phpunit/phpunit": "^11.0", "phpstan/phpstan": "^2.0" },
  "scripts": {
    "test": "phpunit --colors=always",
    "analyse": "phpstan analyse --memory-limit=1G",
    "check": ["@test", "@analyse"]
  }
}

Production practice

Contract

Read environment at the composition root and pass typed config or constructed services inward.

Verification

Boot with each environment profile and assert required, malformed, and unsafe combinations fail immediately.

Operations

Use a secret manager, rotate credentials, and expose configuration fingerprints—not values—for diagnosis.

Common failure mode

A committed .env file is still a secret leak even if the repository is private. History, forks, logs, and build artifacts expand its lifetime.

Independent workshop

Create a production-ready bootstrap for web, CLI, worker, and test entry points sharing one validated configuration model.

Your finished workshop must include:

  • Typed config loader and safe example file
  • Composer install/check scripts
  • Environment matrix and secret-rotation note

Definition of done

Run the happy path and at least two failure paths, explain one design tradeoff in a short README, and leave the code formatted and ready for review.

Recap & quick check

Key takeaways

  • Deployments vary through configuration, not source edits.
  • Configuration should be validated once.
  • Secrets need managed storage and rotation.
  • Composer scripts create repeatable workflows.

Quick check

1. Where should environment reads happen?

2. Should .env containing secrets be committed?

3. Why commit composer.lock for an app?

Keep the workshop: later phases deliberately build on these boundaries, so today's small example can become part of your portfolio architecture.