New features are the right time to refactor. If you can't make the code not complete shit you don't have time to add the feature. Never refactor code to make it prettier or whatever, refactor it when it becomes not-fit-for-purpose for what you need to do. There's obviously exceptions (both ways) but those are exceptions not rules.
My company didn't even have time to keep the dependencies up to date so now we are stuck with Laravel 5 and Vue 2. Refactoring/Updating can be an incredible workload. Personally I'd say rewriting the whole thing would be more efficient but that's not my choice to make.
If you have plenty of time for a task, I fully agree with you.
I was in an organisation that made decent money on a system built on Laravel 3, I think. The framework was written in an only static classes style, which they over ten years had run with while building the business so everything was static classes. Once you have a couple of million lines of that, rewrite is practically impossible because you need to take the team of two OK devs and a junior off firefighting and feature development for years and that will hurt reputation and cashflow badly.
My compromise was to start editing Laravel and implementing optimisations and caching, cutting half a second on every request within a month of starting, and then rewriting crude DIY arithmetic on UNIX epoch into standard library date/time/period functions and similar adjustments. I very openly pushed that we should delete at least two hundred thousand lines over a year which was received pretty poorly by management. When I left in anger due to a googler on the board fucking up the organisation with their annoying vision where this monster was to become "Cloud Native" on GCP credits he had, a plan as bad as a full rewrite, it only took a few months until someone finally convinced them to go through with deletions and cut LoC in half in about six months.
I don't think they do containers or automatic tests yet, probably never will, but as of yet the business survives.
I usually am in favor of a complete rewrite. I'd also prefer to not grow projects into multi million line monoliths. Just make multiple smaller ones that can interact independently with each other. Much simpler structure. Also safer in the long run.
You actually believe that? Distributed systems are simpler than monolithic? In PHP?
This business wouldn't exist if they attempted to follow your advice, because they weren't able and anyway didn't have the money to hire that many developers. There were a couple of subsystems they tried to implement the way you suggest, e.g. one for running certain background jobs.
It was a database table with one row per type of job and a little metadata like job status and a copy of the input. They started jobs by sending a HTTP request. This was a constant source of manual handling, because things started jobs and then crashed and never reset the status and things like that. You could respond that they should have used a message queue instead and so on, but the thing is, they didn't know how to build reliable distributed systems. Few developers do.
At least, that's what I teach our devs.