Applying Rector Rules Interactively in PhpStorm with Diff Preview
AI generated
IDE
{ }
PhpStorm · Rector · Refactoring
Applying Rector Rules Interactively in PhpStorm with Diff Preview
Preview diffs before applying and manage project-specific rector.php configurations

Rector can modernize entire codebases automatically, but blindly running a batch over a mature Magento module is a risk. From PhpStorm, every rule can be applied selectively and with a preview, before it actually touches a file.

14 min read Rector Refactoring PHP 8.4 Automation

1. What Rector is good for in a Magento project

Rector is a tool for automated code transformation: it reads PHP code as an AST, applies defined rules, and writes the transformed code back. Typical use cases in a Magento project are retrofitting constructor property promotion into older classes, replacing the outdated array() syntax with the short form, or automatically adding type declarations where PHPStan can already infer an unambiguous type.

The decisive difference from a simple search-and-replace operation is that Rector understands the code structurally. A rule such as AddVoidReturnTypeWhereNoReturnRector reliably detects whether a method truly never returns a value, even across several nested control structures, and only then adds the void return type. This makes Rector considerably safer for large-scale modernization than regular expressions.

2. Setting up Rector support in PhpStorm

A dedicated plugin from the PhpStorm marketplace integrates Rector directly into the IDE, so rules no longer have to be run exclusively from the terminal but can be started via right-click on a file or a directory in the project tree. Under the hood the integration still uses the rector/rector package installed via Composer in the project and its configured PHP version, so no separate configuration is needed for the IDE.

For the Mark Shust Docker setup this concretely means Rector gets installed as a dev dependency via bin/composer require --dev rector/rector and is then usable both via bin/cli vendor/bin/rector process and via the PhpStorm integration, provided the IDE's PHP interpreter is correctly mapped to the container.


# Install Rector as a dev dependency
bin/composer require --dev rector/rector

# Test run without changes (dry run) right inside the container
bin/cli vendor/bin/rector process app/code/Mironsoft/SeoSuite --dry-run

3. Understanding and using a project-specific rector.php in PhpStorm

Rector is controlled via a rector.php configuration file in the project root, where rule sets and individual rules are explicitly enabled. For a Magento project it makes sense to deliberately restrict the scope to app/code/Mironsoft and explicitly exclude vendor code and generated files via withSkip(), since Rector would otherwise try to transform Magento core code as well, which is neither sensible nor desired.

PhpStorm reads this rector.php when starting the integration and shows only the rules actually enabled in the project in the rule selection, not the entire Rector rule library. This matters because it prevents accidentally applying a rule that was never intended in the project context, for instance a rule from a level set for a PHP version not yet defined as the project's target.


<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php84\Rector\Param\PromoteNullOrFalseFalsyPropertyRector;
use Rector\Set\ValueObject\LevelSetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app/code/Mironsoft'])
    ->withSkip([
        __DIR__ . '/vendor',
        __DIR__ . '/generated',
    ])
    ->withSets([LevelSetList::UP_TO_PHP_84])
    ->withRules([PromoteNullOrFalseFalsyPropertyRector::class]);

4. Using the diff preview before applying a rule

The central safety mechanism, both in plain CLI usage and in the PhpStorm integration, is dry-run mode. Rector shows a complete diff for every file a rule would change, without actually writing the file. In PhpStorm this diff appears in the IDE's familiar diff viewer, so changes can be reviewed file by file, accepted or discarded individually, instead of blindly accepting an entire batch run.

For a rule such as ClassPropertyAssignToConstructorPromotionRector, which replaces existing property assignments in a constructor with constructor property promotion, this preview pays off especially: for classes with complex constructor logic, such as conditional assignments or extra validation in the constructor body, the automatic transformation can lead to slightly divergent semantics. The diff makes such edge cases visible before they get merged unchecked.


- private StoreManagerInterface $storeManager;
-
- public function __construct(StoreManagerInterface $storeManager)
- {
-     $this->storeManager = $storeManager;
- }
+ public function __construct(
+     private readonly StoreManagerInterface $storeManager
+ ) {
+ }

5. Applying individual rules instead of entire rule sets

Instead of applying a complete level set like UP_TO_PHP_84 to an existing module in one pass, it is safer in practice to deliberately select individual rules one after another. The PhpStorm integration lets you pick a single rule from the list of project-enabled rules and apply only that one to a file or directory, which keeps the diff per pass considerably smaller and easier to review.

A proven approach for modernizing an existing Mironsoft module: apply and commit only type-declaration rules first, then separately constructor-property-promotion rules, then array-syntax rules. Each of these steps produces its own, clearly traceable commit, which makes code review noticeably easier compared to a single giant Rector commit with hundreds of lines spanning several unrelated topics.

6. Pitfalls of Rector in Magento contexts

Magento uses reflection-based mechanisms in several places, for instance dependency injection via constructor parameter names in di.xml virtual types or preferences. A Rector rule that renames parameters or automatically changes constructor signatures can, in such cases, cause a silent incompatibility with the XML configuration that only surfaces as an error at runtime, not already at the PHPStan stage.

This is why, in Magento projects, it is important to search specifically for associated di.xml entries referencing the parameter name, for instance in argument-name attributes, after every Rector run touching constructor parameters. PhpStorm helps here through project-wide search for the parameter name, but the check itself is not automated by Rector, it remains a manual follow-up step.


<type name="Mironsoft\SeoSuite\Model\MarkupProvider">
    <arguments>
        <argument name="storeManager" xsi:type="object">Magento\Store\Model\StoreManagerInterface</argument>
    </arguments>
</type>

7. Rector and PHPStan as aligned tools

Rector and PHPStan have a natural order: Rector changes code structurally, PHPStan afterward checks whether the changed code is still type-correct. After every Rector run, even one carefully reviewed with a diff preview, bin/analyse app/code/Mironsoft/SeoSuite --level=5 should therefore be run again to confirm no new level 5 errors were introduced.

In practice, many rules from the TypeDeclarationRector family, such as AddReturnTypeDeclarationRector, actually fix existing PHPStan errors, because they add missing type declarations that PHPStan previously could only derive from PHPDoc or not at all. This way Rector can actively contribute to PHPStan level 5 conformance instead of being just an independent modernization tool.

8. Documenting Rector runs traceably for the team

Because Rector commits often touch many files at once, but are mechanically low-risk in content, it has proven useful to clearly separate them from functional changes and explicitly name the applied rule or rule set in the commit message. A commit like 'Rector: applied ClassPropertyAssignToConstructorPromotionRector to SeoSuite' immediately lets reviewers know this is a mechanical transformation, not a functional change.

For the dual-vendor workflow between the Mironsoft and Abrams copies, this additionally means a Rector run should be executed separately on both paths, since the automatic transformation has no way of knowing that two directories contain structurally identical code. Running Rector only on the Mironsoft copy without the matching run on the Abrams copy would otherwise let the two codebases drift apart gradually.

9. A practical checklist for safe Rector usage

For a controlled Rector deployment on an existing module, the following sequence has proven effective: restrict rector.php to the specific module directory, run a dry run and review the diff completely, apply individual rules rather than whole sets when in doubt, run PHPStan again after applying changes, and finally search specifically for di.xml references to changed constructor parameters.

This sequence turns Rector from a risky batch tool into a controlled part of modernization, where every change was visible before it was actually written. The time savings compared to manual modernization remain intact, only the loss of control from an unsupervised batch run is eliminated.

Step Tool Goal Risk without this step
Dry run with diff Rector --dry-run / PhpStorm integration See changes before they are written Unnoticed semantic drift
Per-rule application PhpStorm Rector rule selection Small, traceable commits Huge, hard-to-review commit
di.xml search PhpStorm project-wide search Find constructor references Silent DI incompatibility at runtime
PHPStan run afterward bin/analyse --level=5 Confirm type correctness after transformation New, unnoticed type errors

Mironsoft

PhpStorm setup, Docker integration, and team productivity

PhpStorm that actually runs optimally for Magento and PHP projects?

We review existing PhpStorm setups for slow indexing, unused Docker integration, and missing team conventions, then set up a configuration that is productive from the first second.

Setup Review

Optimizing indexing, interpreter, and memory settings for large Magento projects.

Docker Integration

Cleanly connecting Xdebug, PHPUnit, and database tools to the Docker setup.

Team Conventions

Standardizing inspection profiles, code style, and live templates project-wide.

10. Summary

Rector in PhpStorm: Key Takeaways

Safety net

Dry-run diff in PhpStorm shows every change before it is actually written

Configuration

rector.php limits scope and rules, PhpStorm shows only project-enabled rules

Magento risk

Constructor changes can break di.xml references, manual follow-up required

Follow-up

Run PHPStan again to confirm type correctness after the transformation

11. FAQ: Rector in PhpStorm: Key Takeaways

1How do I integrate Rector into PhpStorm?
Via a Rector plugin from the PhpStorm marketplace, which under the hood uses the project's own rector/rector package installed through Composer.
2What exactly does the diff preview show?
For every affected file, a complete before-and-after comparison in PhpStorm's familiar diff viewer, without the file actually being written yet.
3Can I apply individual Rector rules instead of whole sets?
Yes, the PhpStorm integration lets you select a single rule enabled in the project, producing smaller and easier-to-review diffs.
4Why should I restrict the Rector scope to app/code/Mironsoft?
So Rector does not attempt to transform Magento core or vendor code, which is neither sensible nor reliably handled by Rector.
5What risk does Rector carry specifically in Magento projects?
Changes to constructor parameters can collide with di.xml references that use the parameter name for dependency injection.
6Do I need to run PHPStan again after a Rector run?
Yes, this confirms that the structural transformation did not introduce new errors at level 5.
7How do I handle rector.php in the dual-vendor workflow?
Run Rector separately on the Mironsoft and the Abrams copy, since the automatic transformation has no awareness of the structural identity between both paths.
8Does Rector fully replace manual refactoring?
No, for complex constructor logic or unusual patterns a manual review of the diff remains necessary before accepting the change.
9How should I commit Rector changes?
Separately from functional changes, explicitly naming the applied rule or rule set in the commit message.
10Where do I place rector.php in the project?
In the project root, with withPaths pointing at the relevant module folder and withSkip excluding vendor and generated directories.