Article

Incremental Modernization for Legacy PHP

Upgrade inherited PHP systems gradually with facades, adapters, routing seams, and staged Composer adoption instead of a risky big-bang rewrite.

Big-bang rewrites of working revenue systems fail more often than staged upgrades. Incremental modernization keeps the legacy app authoritative while you replace seams: one route, one module, one dependency boundary at a time—with tests and rollbacks at each step.

Patterns that work in PHP estates

  • Facade around old code: new entrypoints call a narrow API that still delegates to legacy classes
  • Service extraction: move a bounded capability (billing, auth email) behind an interface
  • Routing seam: send selected URL paths to new code; leave the rest on the old front controller
  • Adapter layers: wrap mysql_* or abandoned libraries until call sites move
  • DB compatibility: keep schemas stable while dual-writing only when absolutely required
  • Composer adoption: autoload first, replace packages later (guide)
TRANSITIONAL — routing seam
# Pseudocode idea: specific paths to new app, default to legacy
location /api/v2/ {
    try_files $uri /public_new/index.php?$query_string;
}
location / {
    try_files $uri /public_legacy/index.php?$query_string;
}

Avoid architecture buzzwords without an executable next step. Each increment should ship: a rollback plan, observability, and a test that would have caught the last failure. Related: testing legacy PHP, inherited app checklist (when published).

Related reading