Рефакторинг legacy кода на PHP: пошаговое руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Рефакторинг legacy кода на PHP: как превратить хаос в порядок

Каждый PHP-разработчик рано или поздно сталкивается с legacy кодом — старым, плохо документированным и часто неработающим проектом. Вместо того чтобы переписывать всё с нуля (что рискованно и дорого), грамотный рефакторинг позволяет улучшить код без остановки бизнес-процессов. В этой статье мы разберём, как безопасно рефакторить legacy PHP-проекты, сохранив их работоспособность.

1. Оценка и подготовка: с чего начать рефакторинг legacy кода

Прежде чем трогать код, необходимо понять его текущее состояние. Пропустите этот этап — и рискуете сломать всё.

  • Создайте резервную копию — полный дамп базы данных и файлов проекта.
  • Проведите аудит — найдите все точки входа, зависимости и "чёрные ящики". Используйте grep для поиска include, require, eval и mysql_* функций.
  • Настройте окружение — поднимите локальную копию проекта (Docker, Vagrant или XAMPP).
  • Добавьте логирование — error_log и мониторинг помогут отследить ошибки после изменений.

Пример простого аудита через консоль:

# Поиск устаревших mysql функций
grep -rn "mysql_query\|mysql_connect\|mysql_fetch" /path/to/legacy/project/

Важно: если в проекте нет тестов — рефакторинг превращается в игру в русскую рулетку. Первым делом покройте критическую логику тестами (даже если это будут ручные сценарии, записанные в документ).

2. Стратегия рефакторинга: маленькие шаги больших изменений

Лучшая стратегия для legacy — постепенное улучшение. Не пытайтесь переписать весь проект за выходные. Используйте подход "бойскаутского правила": оставляй код чище, чем он был до тебя.

2.1. Изолируйте изменения

Каждое изменение должно быть минимальным и атомарным. Пример: переименование переменной в одном файле, затем — извлечение дублирующегося кода в функцию.

<?php
// До рефакторинга (legacy)
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];
$result = mysql_query($sql);

// После: хотя бы экранируем
$id = (int)$_GET['id'];
$sql = "SELECT * FROM users WHERE id = $id";
$result = mysqli_query($link, $sql);
?>

2.2. Используйте инструменты автоматизации

  • PHPStan — статический анализ, находит ошибки без запуска кода.
  • Rector — автоматический рефакторинг (PSR-12, замена устаревших функций).
  • PHP CodeSniffer — проверка стиля кода.
  • PHPUnit — модульное тестирование.

Пример запуска Rector для замены mysql_* на mysqli_*:

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

3. Конкретные приёмы рефакторинга PHP-кода

3.1. Замена "спагетти-кода" на ООП

Legacy часто пишется как один огромный файл с HTML и PHP вперемешку. Разделите логику на классы и функции.

<?php
// Плохо: код вперемешку
$user = getUser($_GET['id']);
echo "<h1>Привет, " . $user['name'] . "</h1>";
if ($_POST['action'] === 'save') {
    saveUser($_POST);
}

// Хорошо: разделение ответственности
class UserController {
    public function show(int $id): void {
        $user = $this->userRepository->find($id);
        $this->render('profile', ['user' => $user]);
    }
}
?>

3.2. Удаление "мёртвого" кода

Неиспользуемые функции, комментарии, закомментированные блоки — всё это создаёт шум. Удаляйте без жалости, но проверьте через git log, не используется ли код где-то ещё.

// Поиск неиспользуемых функций (требуется PHPStan)
vendor/bin/phpstan analyse src/ --level 8

3.3. Переход на современные PSR-стандарты

Автозагрузка PSR-4, использование Composer, отказ от global и require в пользу DI-контейнеров.

// До: ручной require
require_once 'lib/User.php';
$user = new User();

// После: автозагрузка Composer
use App\Entity\User;
$user = new User();

4. Безопасность при рефакторинге: как не сломать бизнес

Даже маленькое изменение может привести к падению продаж или ошибкам в расчётах. Соблюдайте правила:

  • Feature toggle — включайте новый код через конфиг, чтобы быстро откатиться.
  • Параллельный запуск — старый и новый код работают одновременно, результаты сравниваются.
  • Code review — каждое изменение должен проверить другой разработчик.
  • CI/CD pipeline — автоматически прогоняйте тесты перед деплоем.

Пример простого feature toggle:

<?php
if (getenv('USE_NEW_PAYMENT') === 'true') {
    $payment = new NewPaymentProcessor();
} else {
    $payment = new LegacyPaymentProcessor();
}
?>

Заключение

Рефакторинг legacy кода на PHP — это не героический подвиг, а рутинная работа, которую можно и нужно автоматизировать. Начните с малого: поставьте PHPStan, напишите хотя бы один тест, замените одну устаревшую функцию. Постепенно проект станет чище, а вы — увереннее в своих действиях.

Помните: идеальный код — это ми

Блоги

Рекомендаций по книгам