composer why-not php 8.0. That is the first command of the migration, and it has nothing to do with syntax.

PHP 8.0 is six weeks old. Twitter is full of match expressions and constructor promotion. Meanwhile the real upgrade of a working project is a dependency problem. Your code is maybe twenty percent of what runs in production. The rest is the framework, thirty packages and a dozen extensions, and any one of them can be the blocker.

The command prints every package whose constraints refuse PHP 8. That list is your backlog. Some packages need one version bump. Some need a major upgrade with its own changelog. One or two are abandoned, and now you have to face it. Better in January than during an incident.

Second, CI runs the suite on 7.4 and 8.0 at the same time. Both green, always. The project stays deployable on 7.4 while you fix 8.0 failures one by one. Most failures live deep inside some library, where the engine got stricter.

Third, before the switch, record baseline numbers. Response times, opcache stats, memory. JIT is loud in benchmarks and quiet in a normal web app, and I want to know what we got, not what the news said.

And the part people skip. After production runs on 8.0, do not touch new syntax for a few more weeks. Named arguments and promoted constructors are a one-way door. The day you merge them, rollback to 7.4 stops being an option. Keep that door open until you are sure you will not need it.

Boring plan. Upgrades should be boring.

I merged a match on day two. Then I reverted it, and nobody noticed either way.