Рефакторинг PHP-кода: когда он нужен и как не навредить проекту
Каждый PHP-разработчик рано или поздно сталкивается с кодом, который хочется переписать. Легаси-проекты на PHP полны «магических чисел» (magic numbers), функций длиной в экран и классов, отвечающих за всё на свете. Руки чешутся навести порядок. Но стоит ли? И если да — как сделать рефакторинг PHP-кода безопасно и эффективно?
В этой статье мы разберём, когда рефакторинг действительно необходим, а когда лучше оставить всё как есть. Вы увидите реальные примеры плохого и хорошего кода на PHP, получите чек-лист действий и поймёте, как не превратить улучшение кода в катастрофу.
Когда рефакторинг PHP-кода оправдан?
Рефакторинг — это изменение внутренней структуры кода без изменения его внешнего поведения. Звучит просто, но на практике это одно из самых рискованных занятий в разработке. Вот признаки, что пора задуматься об улучшении PHP-кода:
- Код «воняет» (code smells). Длинные методы, дублирование, классы-боги (God objects), непонятные имена переменных.
- Добавление новой функциональности становится мучением. Если каждый пулл-реквест ломает три других места — это звоночек.
- Вы не понимаете, что делает метод через неделю после его написания. Плохой код — это код, который требует комментариев к каждой строчке.
- Нарушен принцип единственной ответственности (SRP). Класс UserManager, который и пользователей создаёт, и письма шлёт, и отчёты генерирует — типичный кандидат на рефакторинг.
Но есть ситуации, когда рефакторинг PHP-кода может навредить:
- Дедлайн завтра, а код работает.
- Нет тестов. Без них любое изменение — игра в русскую рулетку.
- Код пишется «на коленке» для прототипа, который завтра выкинут.
Правила безопасного рефакторинга
Прежде чем браться за рефакторинг PHP-кода, запомните три железных правила:
- Покройте код тестами. Хотя бы интеграционными. Если тестов нет — напишите их для критических участков.
- Рефакторите маленькими шагами. Один метод за раз. Запушили — проверили — пошли дальше.
- Не смешивайте рефакторинг и добавление фич. Это две разные задачи. Делайте их в разных коммитах.
Примеры рефакторинга PHP-кода: от плохого к хорошему
Давайте посмотрим на реальные примеры. Допустим, у нас есть функция для расчёта скидки. Вот как она выглядит в типичном легаси-проекте:
До рефакторинга (плохой код)
function calculateDiscount($user, $order) {
$discount = 0;
if ($user->isVip()) {
$discount = 10;
if ($order->getTotal() > 1000) {
$discount = 15;
}
}
if (date('Y-m-d') == '2025-12-31') {
$discount = $discount + 5;
}
if ($order->getItemsCount() > 5) {
$discount = $discount + 3;
}
return $discount;
}
Проблемы: магические даты, числа-константы, смесь логик (пользователь, заказ, дата). Если завтра появится новая акция — функция станет ещё длиннее.
После рефакторинга PHP (хороший код)
class DiscountCalculator {
private const NEW_YEAR_DATE = '2025-12-31';
public function calculate(User $user, Order $order): int {
$discount = $this->getBaseDiscount($user)
+ $this->getHolidayBonus()
+ $this->getVolumeBonus($order);
return min($discount, 50); // не больше 50%
}
private function getBaseDiscount(User $user): int {
if ($user->isVip() && $user->getTotalSpent() > 1000) {
return 15;
}
return $user->isVip() ? 10 : 0;
}
private function getHolidayBonus(): int {
return (date('Y-m-d') === self::NEW_YEAR_DATE) ? 5 : 0;
}
private function getVolumeBonus(Order $order): int {
return ($order->getItemsCount() > 5) ? 3 : 0;
}
}
Теперь каждый метод отвечает за свою логику. Добавить новую акцию? Просто создайте новый метод. И это — отличный пример рефакторинга PHP-кода, который делает систему гибкой.
Как рефакторить PHP: пошаговая инструкция
Начните с малого. Вот план действий для безопасного улучшения PHP-кода:
Шаг 1. Выделите «узкое место»
Не пытайтесь переписать весь проект сразу. Найдите самый болезненный участок — например, класс с 3000 строк или функцию, которая используется в 50 местах.
Шаг 2. Напишите тесты
Даже если это простой assert() в начале скрипта. Убедитесь, что текущее поведение зафиксировано.
Шаг 3. Изменяйте по одному паттерну
Вот самые полезные техники для рефакторинга PHP:
- Извлечение метода (Extract Method). Разбейте длинную функцию на несколько маленьких.
- Замена магического числа константой (Replace Magic Number with Symbolic Constant). Вместо
if ($x > 86400)пишитеif ($x > self::SECONDS_IN_DAY). - Инкапсуляция поля (Encapsulate Field). Сделайте свойства приватными, добавьте геттеры/сеттеры.
- Замена наследования делегированием (Replace Inheritance with Delegation). Композиция часто лучше наследования.
Шаг 4. Запустите тесты
Зелёные тесты — зелёный свет. Если что-то упало — откатывайте изменения.
Шаг 5. Сделайте коммит с осмысленным сообщением
Не пишите «fix» или «refactoring». Укажите, что именно изменили: «Extract method calculateTax from OrderProcessor».
Инструменты для рефакторинга PHP-кода
Хороший разработчик использует инструменты. Вот что поможет вам при рефакторинге PHP:
- PHPStan — статический анализатор. Найдёт ошибки до того, как вы запустите код.
- Rector — автоматический рефакторинг. Может заменить устаревшие функции,