Rector для Laravel: автоматический рефакторинг и обновление кода на практике — PROG-TIME

Rector для Laravel: автоматический рефакторинг и обновление кода на практике

17.06.2026

Обновление версии Laravel или PHP в большом проекте — это всегда десятки часов рутины: заменить устаревшие хелперы, переписать legacy-фабрики, добавить типы, вычистить мёртвый код. Делать это руками долго и опасно — легко пропустить место или внести ошибку. Здесь на помощь приходит Rector — инструмент, который анализирует код на уровне абстрактного синтаксического дерева (AST) и применяет заранее описанные правила трансформации автоматически.

В этой статье разберём на практике, как подключить Rector к Laravel-проекту, безопасно обновить версию PHP и фреймворка, навести порядок в коде с помощью наборов правил и встроить всё это в CI. Все команды и конфиги проверены по официальной документации getrector.com и пакету driftingly/rector-laravel (актуальная версия 2.5.0).

Что такое Rector и зачем он нужен

Rector — это CLI-инструмент для PHP, который умеет делать две вещи: instant upgrades (автоматически применять breaking changes при переходе между версиями PHP и фреймворков) и refactoring (улучшать качество кода — добавлять типы, упрощать конструкции, удалять дублирование). В отличие от обычного поиска с заменой по регулярным выражениям, Rector понимает структуру кода: он строит AST, находит нужные узлы и переписывает их корректно, сохраняя форматирование.

Работает Rector нативно на PHP 7.2 и выше. Это значит, что даже старый проект можно постепенно подтягивать к современным стандартам. Главный принцип работы с инструментом — не торопиться: применять правила небольшими порциями, чтобы каждый pull request было легко отревьюить и смержить.

Установка и первый запуск

Ставим Rector как dev-зависимость через Composer:

composer require rector/rector --dev

Теперь создадим базовый конфиг rector.php в корне проекта. Современный синтаксис конфигурации — текучий (fluent) интерфейс через RectorConfig::configure():

<?php

use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/app',
        __DIR__ . '/config',
        __DIR__ . '/database',
        __DIR__ . '/routes',
        __DIR__ . '/tests',
    ]);

Запускать Rector нужно всегда сначала в режиме предпросмотра — флаг --dry-run покажет диф изменений, но не тронет файлы:

vendor/bin/rector --dry-run

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

vendor/bin/rector

Обновление PHP — по одному набору за раз

Самая частая задача — подтянуть синтаксис под актуальную версию PHP. Добавляем в конфиг метод withPhpSets():

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app', __DIR__ . '/tests'])
    ->withPhpSets();

Но здесь есть важный нюанс. Пустой withPhpSets() возьмёт версию из composer.json и применит все наборы вплоть до неё — это могут быть сотни правил разом. Ревьюить такой PR невозможно. Поэтому документация Rector рекомендует включать версии по одной:

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app', __DIR__ . '/tests'])
    ->withPhpSets(php83: true);

Прогнали, проверили диф, смержили — и только потом переходим к php84: true и дальше. Такой пошаговый подход превращает рискованную миграцию в серию маленьких безопасных коммитов.

Наборы качества кода

Помимо версионных апгрейдов, Rector умеет улучшать сам код. Для этого есть «подготовленные наборы», которые включаются через withPreparedSets():

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app', __DIR__ . '/tests'])
    ->withPreparedSets(
        deadCode: true,
        codeQuality: true,
        typeDeclarations: true,
        earlyReturn: true,
    );

Набор deadCode вычистит недостижимые ветки и неиспользуемые переменные, codeQuality упростит избыточные конструкции, typeDeclarations добавит типы аргументов и возвращаемых значений, а earlyReturn переведёт вложенные условия на ранний возврат. Как и с PHP-наборами, лучше включать их по одному.

Rector для Laravel

Базовый Rector ничего не знает о специфике фреймворка. Чтобы получить правила именно для Laravel (и связанных пакетов вроде Cashier и Livewire), ставим расширение, которое поддерживает сообщество:

composer require --dev driftingly/rector-laravel

Самый удобный сценарий — автоматическое определение нужных правил по версиям пакетов из composer.json. Для этого подключаем провайдер наборов:

<?php

use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelSetProvider;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app', __DIR__ . '/tests'])
    ->withSetProviders(LaravelSetProvider::class)
    ->withComposerBased(laravel: true);

Если хочется контролировать целевую версию вручную, используйте уровневые наборы из LaravelLevelSetList — наборы для старших версий включают в себя младшие:

use RectorLaravel\Set\LaravelLevelSetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app'])
    ->withSets([
        LaravelLevelSetList::UP_TO_LARAVEL_130,
    ]);

Тематические наборы и точечные правила Laravel

Отдельно от версионных апгрейдов есть наборы из LaravelSetList, улучшающие конкретные аспекты кода:

use RectorLaravel\Set\LaravelSetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app'])
    ->withSets([
        LaravelSetList::LARAVEL_CODE_QUALITY,
        LaravelSetList::LARAVEL_COLLECTION,
        LaravelSetList::LARAVEL_IF_HELPERS,
        LaravelSetList::LARAVEL_ARRAY_STR_FUNCTION_TO_STATIC_CALL,
    ]);

Например, набор LARAVEL_IF_HELPERS заменит конструкции вида if (...) { abort(403); } на лаконичный хелпер abort_if(...), а LARAVEL_COLLECTION перепишет цепочки методов коллекций на более читаемые и эффективные варианты.

Часть правил требует ручной настройки — их добавляют через withConfiguredRule(). Классический пример — вычистка отладочных вызовов перед релизом:

use RectorLaravel\Rector\FuncCall\RemoveDumpDataDeadCodeRector;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app'])
    ->withConfiguredRule(RemoveDumpDataDeadCodeRector::class, [
        'dd', 'dump', 'var_dump',
    ]);

Полезны и такие правила, как RouteActionCallableRector (превращает строковые экшены вида 'UserController@index' в массив [UserController::class, 'index']) и WhereToWhereLikeRector (заменяет where('col', 'like', $v) на современный whereLike('col', $v)).

Пропуск правил и файлов

Не каждое правило безопасно применять везде. Чтобы исключить конкретное правило или каталог, используйте withSkip():

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app'])
    ->withSkip([
        __DIR__ . '/app/Legacy',
        RemoveDumpDataDeadCodeRector::class,
    ]);

Интеграция в CI/CD

Чтобы код не «разъезжался», запускайте Rector в пайплайне в режиме проверки. В CI используется тот же --dry-run: если Rector нашёл, что можно изменить, он завершится с ненулевым кодом и провалит сборку. Пример шага для GitHub Actions:

- name: Rector check
  run: vendor/bin/rector --dry-run

Так разработчики будут обязаны прогонять Rector локально до пуша. Для ускорения на больших проектах включите кеширование — Rector хранит результаты анализа и не перепроверяет неизменённые файлы.

Итоги

Rector превращает миграции и рефакторинг из многодневной рутины в управляемый и предсказуемый процесс. Ключевые принципы работы: ставим rector/rector и расширение driftingly/rector-laravel, всегда сначала запускаем --dry-run, включаем наборы по одному и оформляем небольшие pull request’ы. Начните с обновления PHP по версиям, затем подключите наборы качества кода и Laravel-специфичные правила, а финальным шагом встройте проверку в CI. В результате вы получаете кодовую базу, которая обновляется быстро, безопасно и без героических усилий всей команды.