Refactoring Legacy PHP Code: A Step-by-Step Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Refactoring legacy PHP code: how to turn chaos into order



Every PHP developer sooner or later encounters legacy code — an old, poorly documented, and often non-working project. Instead of rewriting everything from scratch (which is risky and expensive), competent refactoring allows you to improve the code without stopping business processes. In this article, we will look at how to safely refactor legacy PHP projects while maintaining their functionality.



1. Assessment and preparation: where to start refactoring legacy code



Before touching the code, you need to understand its current state. Skip this stage — and you risk breaking everything.



  • Create a backup — a full dump of the database and project files.
  • Conduct an audit — find all entry points, dependencies, and "black boxes". Use grep to search for include, require, eval, and mysql_* functions.
  • Set up the environment — spin up a local copy of the project (Docker, Vagrant, or XAMPP).
  • Add logging — error_log and monitoring will help track errors after changes.


Example of a simple audit via the console:



# Search for deprecated mysql functionsgrep -rn "mysql_query\\|mysql_connect\\|mysql_fetch" /path/to/legacy/project/


Important: if the project has no tests — refactoring turns into a game of Russian roulette. First, cover the critical logic with tests (even if they are manual scenarios written down in a document).



2. Refactoring strategy: small steps for big changes



The best strategy for legacy is gradual improvement. Don't try to rewrite the entire project in one weekend. Use the "boy scout rule" approach: leave the code cleaner than you found it.



2.1. Isolate changes



Each change should be minimal and atomic. Example: renaming a variable in one file, then extracting duplicate code into a function.



<?php// Before refactoring (legacy)$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];$result = mysql_query($sql);

// After: at least escape it$id = (int)$_GET['id'];$sql = "SELECT * FROM users WHERE id = $id";$result = mysqli_query($link, $sql);?>


2.2. Use automation tools



  • PHPStan — static analysis, finds errors without running the code.
  • Rector — automatic refactoring (PSR-12, replacing deprecated functions).
  • PHP CodeSniffer — code style checking.
  • PHPUnit — unit testing.


Example of running Rector to replace mysql_* with mysqli_*:



vendor/bin/rector process src/ --set mysql-to-mysqli


3. Specific refactoring techniques for PHP code



3.1. Replacing "spaghetti code" with OOP



Legacy is often written as one huge file with HTML and PHP mixed together. Separate the logic into classes and functions.



<?php// Bad: mixed code$user = getUser($_GET['id']);echo "<h1>Hello, " . $user['name'] . "</h1>";if ($_POST['action'] === 'save') {    saveUser($_POST);}

// Good: separation of concernsclass UserController { public function show(int $id): void { $user = $this->userRepository->find($id); $this->render('profile', ['user' => $user]); }}?>


3.2. Removing "dead" code



Unused functions, comments, commented-out blocks — all of this creates noise. Delete without mercy, but check via git log that the code isn't used somewhere else.



// Search for unused functions (requires PHPStan)vendo                

Blogs

Book Recommendations