Symfony 5.0 is 4.4 minus everything deprecated. That one sentence is the whole upgrade plan. Both land in November, and if the application runs on 4.4 with zero deprecation warnings, the major is a version bump. Two months is enough to get there in small chunks, with no freeze and no heroic branch that lives for six weeks.
The order that works for me.
First, get to 4.3 and make the deprecation report visible. The PHPUnit bridge prints the summary after the test run. In dev, the profiler collects the same warnings per request. You cannot clean what you do not see. The first report will be depressing. Fine. It is a todo list, not a verdict.
Second, sort the list by who owns the warning. Your own code you fix directly, most items are mechanical renames and take minutes. Warnings from vendors you fix with composer update of the direct dependencies, somebody upstream usually did the work already. What remains is the honest problem: abandoned bundles that will never see a 5.0 release. Every legacy project has two or three. For each one the choice is fork, replace, or inline the ten percent of it you actually use. Decide now. Not in November with a broken composer update on the screen.
Third, before touching anything, cover the critical paths with tests. Not full coverage. Checkout, login, the money flows. Deprecation fixes are supposed to be behavior-neutral. “Supposed to” is doing a lot of work in that sentence.
And a scar. An upgrade branch attracts refactoring. You rename a method and suddenly want to redesign the whole service. I did that once. Mandatory changes go in the upgrade, desirable changes go in the backlog. Mixing them is how two months become six.