Рефакторинг PHP-кода: когда он нужен и как не навредить проекту

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

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

Начать курс

Рефакторинг PHP-кода: когда он нужен и как не навредить проекту

Каждый PHP-разработчик рано или поздно сталкивается с кодом, который хочется переписать. Легаси-проекты на PHP полны «магических чисел» (magic numbers), функций длиной в экран и классов, отвечающих за всё на свете. Руки чешутся навести порядок. Но стоит ли? И если да — как сделать рефакторинг PHP-кода безопасно и эффективно?

В этой статье мы разберём, когда рефакторинг действительно необходим, а когда лучше оставить всё как есть. Вы увидите реальные примеры плохого и хорошего кода на PHP, получите чек-лист действий и поймёте, как не превратить улучшение кода в катастрофу.

Когда рефакторинг PHP-кода оправдан?

Рефакторинг — это изменение внутренней структуры кода без изменения его внешнего поведения. Звучит просто, но на практике это одно из самых рискованных занятий в разработке. Вот признаки, что пора задуматься об улучшении PHP-кода:

  • Код «воняет» (code smells). Длинные методы, дублирование, классы-боги (God objects), непонятные имена переменных.
  • Добавление новой функциональности становится мучением. Если каждый пулл-реквест ломает три других места — это звоночек.
  • Вы не понимаете, что делает метод через неделю после его написания. Плохой код — это код, который требует комментариев к каждой строчке.
  • Нарушен принцип единственной ответственности (SRP). Класс UserManager, который и пользователей создаёт, и письма шлёт, и отчёты генерирует — типичный кандидат на рефакторинг.

Но есть ситуации, когда рефакторинг PHP-кода может навредить:

  • Дедлайн завтра, а код работает.
  • Нет тестов. Без них любое изменение — игра в русскую рулетку.
  • Код пишется «на коленке» для прототипа, который завтра выкинут.

Правила безопасного рефакторинга

Прежде чем браться за рефакторинг PHP-кода, запомните три железных правила:

  1. Покройте код тестами. Хотя бы интеграционными. Если тестов нет — напишите их для критических участков.
  2. Рефакторите маленькими шагами. Один метод за раз. Запушили — проверили — пошли дальше.
  3. Не смешивайте рефакторинг и добавление фич. Это две разные задачи. Делайте их в разных коммитах.

Примеры рефакторинга 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 — автоматический рефакторинг. Может заменить устаревшие функции,

Блоги

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