azyware
Technology

Migrating PHP 5 to PHP 8 in a live business system

EZ
Eazyware
· 7 min read
Quick answer

What should you know about a PHP 5 to PHP 8 migration in a live system?

Upgrade slice by slice with characterisation tests as the gate, scheduled around the business calendar, with rehearsed rollback. Stage through 7.4, fix deprecations before they become fatal errors, replace removed extensions, and run each slice on the new runtime in parallel before switching traffic.

A PHP 5 to PHP 8 migration is not a version bump. PHP 5 reached end of life years ago, the runtime between then and now removed whole extensions, changed how errors, types and comparisons behave, and made many silent warnings into fatal exceptions. A business system that has run for a decade on PHP 5 will contain code that depends on every one of those old behaviours. The safe way through is the same as any legacy PHP modernization: capture current behaviour with tests, upgrade in slices, schedule around the calendar and rehearse the way back. This article sets out the sequence, the specific PHP migration risks, and what it takes in team and time.

Why the migration matters now

Three pressures usually bring a PHP 5 system to the table at once. Security, because unsupported runtimes receive no patches and auditors and cyber-insurers have started asking. Hosting, because current operating systems and managed platforms no longer ship PHP 5, so every server rebuild becomes an archaeology project. And capability, because the libraries needed for payments, messaging and AI integration require modern PHP. The longer the gap, the larger each of those bills becomes, and the fewer engineers are willing to work on it.

What changes between PHP 5 and PHP 8

AreaPHP 5 behaviourPHP 8 behaviourTypical impact
Database accessmysql_* functionsRemoved; mysqli or PDO onlyEvery query site in old code
Error handlingWarnings and notices, execution continuesMany become TypeError or ValueError exceptionsSilent failures become crashes
String and number comparisonLoose, surprising coercionsSaner comparisons; 0 == "abc" is falseConditionals that relied on old rules
Constructors and classesPHP 4-style constructors, each() and create_function()RemovedOld libraries and helper code
Regular expressionsereg family availableRemoved; preg onlyValidation and parsing code
Type handlingMostly untyped, implicit conversionStrict types available, internal functions stricterArithmetic on strings, null arguments
Extensionsmcrypt, mysql, ereg and othersRemoved or moved to PECLEncryption and legacy integrations
PerformanceInterpreter of its eraFar faster runtime with JIT optionA benefit, once behaviour is preserved

The sequence that works

Inventory before anything else

Run static analysis across the whole codebase to list removed functions, deprecated constructs and incompatible syntax. Inventory every extension the system loads, every third-party library and its version, and every cron job and script outside the main application that also runs on the old runtime. The forgotten nightly script that emails the finance report is where most surprises live. The PHP project's own UPGRADING notes in the php-src repository list every backward-incompatible change per release and are the primary reference for this step.

Build the safety net

Before changing code, record what the system does. Pull a stratified sample of real requests, jobs and reports, run them on the current PHP 5 system and store the outputs as a golden master. This is the characterisation suite, and it is the gate for every step that follows. We describe how to build one in characterisation tests for legacy code. Without it, the migration is a series of guesses checked by users.

Stage through an intermediate version

Jumping directly from 5.x to 8.x compounds every change at once and makes failures hard to attribute. Staging through 7.4 splits the work: the 5-to-7 step handles removed extensions and the mysql_* rewrite; the 7-to-8 step handles stricter types, comparison changes and the warnings that became exceptions. Deprecation notices on 7.4 are the to-do list for 8. Each stage runs the golden master suite until it is green.

Slice the codebase

A monolith can rarely be upgraded in one commit, but it can be upgraded in slices if the runtime boundary is drawn carefully. Standalone scripts and cron jobs move first. Then modules that can be routed through a façade, so that a request for that module hits a PHP 8 process while the rest still hits PHP 5. Shared code is made compatible with both runtimes during the transition, which is a deliberate constraint that keeps every slice reversible. This is the strangler pattern applied to a runtime rather than an architecture.

Parallel run, switch, watch

Each slice runs on the new runtime in parallel with the old, receiving the same traffic and having its output compared. When the comparison is clean over a full business cycle for that module, traffic is switched at the façade. If error rates or business metrics move, the switch is reversed. Rollback is configuration, not a redeploy, and it is rehearsed on a quiet day before the first real switch.

PHP migration risks that bite in production

  • Loose comparisons in access control or pricing logic that behave differently under PHP 8's saner rules
  • Numeric strings from form fields and CSV imports that now throw where they used to coerce
  • Encryption built on mcrypt, where the replacement must decrypt every existing record before the old code is gone
  • Session and serialisation formats that differ between runtimes when both are live at once
  • Third-party libraries pinned to versions that no longer exist, some with no maintained successor
  • Warnings suppressed with @ for a decade that are now fatal errors nobody sees until a job dies at 2 a.m.

Scheduling around the business

The calendar is a first-class input. No switch-over during month-end close, a fee window, an exam period or a peak sales season. Each slice is given a window with a quiet period after it long enough to observe one full cycle of its work, and a named business owner who signs off before the old runtime for that slice is removed. Writing the blackout dates into the plan at the start is what stops the migration from being pushed by an engineering deadline into a week the business cannot afford.

What you get on the other side

Once the system is on PHP 8, three things become possible that were not. Modern libraries for payments, messaging and identity install cleanly. Hosting moves to any current platform, including containers, without custom builds. And the codebase can be given an API layer that lets AI extraction, search and copilots sit beside it, which is the point at which the modernisation starts returning value beyond risk reduction. That path from upgrade to AI capability is what our legacy-to-AI modernization programme is built around, and the custom enterprise software team handles the modules that are better replaced than upgraded.

A worked example

A university's fee and admissions system ran on PHP 5 with a vendor who had left the market. The inventory found the main application, two dozen cron scripts and a reporting module that used mcrypt for stored identifiers. The characterisation suite was built from a term's worth of real requests and reports. Standalone scripts moved to PHP 8 first, then results publication behind a façade, timed after an exam cycle. Fees moved outside the collection window with a parallel run through one cycle; mcrypt-encrypted records were re-encrypted by a batch job before the old code was retired. Admissions moved last, with the parallel run spanning an intake. Staff saw no downtime. The university ERP case study covers the wider modernisation.

Team and timeline

A migration of this kind runs with an architect who owns the slice plan and calendar, two backend engineers on the code, a QA engineer on the golden master suite and comparison tooling, and a DevOps engineer for the dual-runtime hosting. Your side provides a business owner per module for sign-off and a systems administrator who knows where the cron jobs live. A mid-sized system fits the ReCore programme at 8–16 weeks from $31,500 / ₹22,40,000; larger estates run as consecutive phases, with the ranges on the pricing page. After cutover the system runs under a Care Plan, and everything, including the test suite, is yours.

Before you start: a checklist

  • Static analysis report of removed and deprecated constructs across the entire codebase
  • Inventory of extensions, libraries, cron jobs and scripts outside the main application
  • A golden master suite built from real requests, jobs and reports
  • A slice plan with standalone scripts first and shared modules last
  • Dual-runtime hosting with a façade that can route per module
  • Blackout windows from the business calendar written into the plan
  • A re-encryption or data conversion plan for anything built on removed extensions
  • A rehearsed rollback for the first slice, on a quiet day, before the first real switch

Questions clients ask

  • Can we go straight from 5.6 to 8.x? You can, but staging through 7.4 makes failures attributable and turns deprecations into a to-do list.
  • Will the site be down? Not if the slices are routed through a façade and switched with rollback; downtime is a planning failure, not a requirement.
  • Should we rewrite instead? Rarely. Upgrade first with the behaviour locked in, then replace the modules that deserve it; see modernization vs rewrite.
  • Can AI do the mechanical rewrites? Much of it, yes, with the golden master suite deciding what is accepted.
  • What about the framework? If the app sits on an old framework version, its upgrade is a slice of its own, planned after the runtime.

See zero-downtime cutovers for switch-over mechanics, adding an API layer to a legacy monolith for the façade, and embedding AI into legacy systems for what comes after.

Inventory, lock in behaviour, stage the runtime, slice the code, switch with a way back, and keep the business calendar in charge of the dates.

Frequently asked questions

How long does a PHP 5 to PHP 8 migration take?

▾

A mid-sized business system with a few hundred thousand lines typically fits an 8–16 week phase once the safety net exists. Large estates with many cron jobs and encrypted data run as consecutive phases, each timed around the business calendar.

What are the biggest risks in upgrading PHP in production?

▾

Removed extensions such as mysql_* and mcrypt, comparison and type changes that alter conditionals silently, and suppressed warnings that become fatal errors. Characterisation tests and parallel runs catch these before users do.

Can you upgrade PHP without downtime?

▾

Yes. Route modules through a façade, run each on the new runtime in parallel, switch traffic per module and keep rollback as a configuration change. Our legacy-to-AI modernization programme plans exactly that.