Skip to content
Insights

Custom software

Refactor or rewrite? A decision guide for legacy PHP applications

How to decide between refactoring and rewriting a legacy PHP application, and how to modernise step by step without stopping the business.

· 4 min read · AKANTIO

Every long-lived PHP application reaches the moment where someone says: "It would be faster to rewrite it." Sometimes that is true. More often, a rewrite takes longer than expected, has to chase a moving target, and loses years of business rules that were never written down anywhere except in the old code.

Here is how we decide between refactoring and rewriting, and how to modernise without stopping the business.

Why rewrites fail

A legacy application is ugly partly because it is full of knowledge: edge cases discovered in production, customer-specific exceptions, workarounds for partner systems. A rewrite starts from a clean specification that does not contain that knowledge. The team then rediscovers it, one bug report at a time, while the old system keeps changing because the business cannot wait.

The result is two systems to maintain and a migration date that keeps moving.

Questions that decide it

Answer these honestly:

  1. Does the application still do the right thing for the business? If the core model is still right and only the code is painful, refactor. If the business has fundamentally changed and the data model no longer fits, a rewrite of that part may be justified.
  2. Can it run on a supported PHP version? Unsupported PHP versions receive no security fixes (see the supported versions page). Getting onto a supported version is the first job either way, and it is usually a refactoring job.
  3. Is the framework still alive? An application on a dead framework, or a home-grown one, may need its foundations replaced. That can still be done piece by piece.
  4. Can you get tests around it? If you can write tests that capture current behaviour, you can refactor safely. If behaviour is impossible to observe, start there.
  5. Who knows how it works? If the knowledge is still in the team, refactoring keeps it. If everyone who understood it has left, both options need archaeology first.

In our experience, the answer is rarely "rewrite everything" or "change nothing". It is usually "replace these parts, keep and clean those".

The strangler approach

The safest way to modernise is to replace the old system gradually, while it keeps running:

  1. Put a front door in place. Route all traffic through something you control: a reverse proxy, the framework's router, or an API layer.
  2. Pick one slice. Choose a feature with clear boundaries and real business value: the order export, the customer portal, the pricing engine.
  3. Build the new version behind the door, with tests, and route that slice to it. Old and new run side by side.
  4. Retire the old code for that slice, then pick the next one.

Each step is small enough to ship in weeks and to roll back if needed. The business sees progress continuously instead of after a long silence.

Refactoring safely

For the parts you keep:

  • Characterisation tests first. Before changing code, write tests that record what it currently does, including the odd behaviour. They are your safety net, not a statement that the behaviour is right.
  • Static analysis. PHPStan or Psalm find type errors and dead code. Start at a low level and raise it gradually, with a baseline for existing issues.
  • Automated upgrades. Rector automates many PHP version and framework upgrades. Review its changes, but let it do the repetitive work.
  • Separate business rules from infrastructure. Move rules out of controllers, templates and SQL into plain classes you can test. Then the database layer or framework can change without touching the rules.
  • Small, frequent releases. A refactoring that lives in a branch for three months is a rewrite in disguise.

Signs a rewrite is the right call

A full rewrite can be right when the application is small enough to rebuild in a few months, when its behaviour is well understood and documented, when the old platform cannot be made secure, or when the product is being replaced by something genuinely different. Even then, migrate data and users in stages, and keep the old system available until the new one has proven itself.

Where to start

Start with an inventory: PHP and framework versions, test coverage, deployment process, the parts that change most often, and the parts that cause the most incidents. That inventory usually makes the decision obvious. It is also the first step of a technical code audit.

We modernise legacy applications as part of our custom software service, and we prefer small steps with tests over big-bang rewrites.

Have a project in mind?

Tell us what you need. We reply within 1 business day with questions or a first estimate.