Article

Managing Legacy Composer Dependencies

Operational strategies for abandoned packages, platform pins, forks, security advisories, and PHP version unlocks in old Composer projects.

Composer is often both the unlock and the blocker for PHP upgrades. A single abandoned package can pin "php": "<=7.4" transitively while CVEs accumulate. This expanded guide replaces the short stub with a working process.

Make the graph visible

composer why-not php 8.3
composer outdated --direct
composer audit
composer depends monolog/monolog

Record direct vs transitive constraints. Many “we cannot move to 8” claims dissolve when an unused package is removed.

Platform configuration without lying

config.platform.php should mirror the runtime you are allowed to deploy—not a fantasy version. Use it to stop CI from resolving packages that need PHP 8.4 while production remains on 8.2, then raise the pin in lockstep with FPM images.

# TRANSITIONAL composer.json
{
  "config": {
    "platform": { "php": "8.2.27" },
    "audit": { "abandoned": "report" }
  },
  "require": {
    "php": "^8.2"
  }
}

Abandoned and unmaintained packages

  1. Prefer official successors (Zend → Laminas components where applicable).
  2. Evaluate maintained forks with clear licenses and release tags.
  3. Wrap a tiny interface around the feature you actually use; delete the rest.
  4. Vendor as last resort with an expiration ticket and owner.

Unlocking PHP versions

Work branch-by-branch: resolve composer why-not php 8.2 on a side branch, run the suite, then bump. Pair with version migration steps so Composer and FPM move together. Scanners still matter for app code outside vendor: compatibility checker, deprecated checker.

Security process

  • Weekly composer audit in CI
  • Time-boxed exceptions with compensating controls
  • No new features while critical advisories lack a plan

Related: legacy audit, inherited applications.

Related reading