Bundling Quality Gates Locally in PhpStorm: PHPStan, PHPUnit, PHPCS, Rector
AI generated
IDE
{ }
PhpStorm · PHPStan · PHPUnit · PHPCS · Rector
Bundling Quality Gates Locally in PhpStorm
PHPStan, PHPUnit, PHPCS and Rector before the commit

If you only find out about quality gates in the CI pipeline, you lose minutes or hours on feedback loops that could have been resolved locally in seconds. PHPStan, PHPUnit, PHPCS and Rector can be integrated into PhpStorm so that errors become visible right at the moment you save, without ever leaving the command line.

18 min read PHPStan · PHPUnit · PHPCS · Rector · External Tools PhpStorm 2025 · PHP 8.4 · Magento 2 · Docker

1. Why quality gates should run locally, not only in CI

The classic approach: write code, push, wait for the result in CI. If PHPStan level 8 finds three spots that are not correct, you fire up the IDE again, find the line, fix it, push again, wait. On a medium-sized PHP project, this cycle easily costs 10 to 20 minutes per round. Multiplied by several commits per day and several developers, that turns into a measurable loss of productivity that can be avoided entirely.

With its external tools, run configurations and native PHPUnit integration, PhpStorm provides all the building blocks needed to pull PHPStan, PHPUnit, PHPCS and Rector directly into the IDE. The result: PHPStan errors show up as a red underline directly in the editor, PHPCS violations are fixed on save, and a Rector run is a single keystroke away. CI then serves only as a final safety net, no longer as the primary feedback tool.

For Magento 2 projects that use PHP 8.4 with strict types, this is particularly relevant. Magento ships many classes with complex types, and PHPStan at level 6 or higher quickly finds real bugs there, but only if the right extensions are loaded. In PhpStorm you can store this configuration once and then be sure, on every single run, that exactly the same analysis executes as in CI.

2. Setting up PHPStan in PhpStorm

PhpStorm has no native PHPStan integration through a dedicated UI panel, but external tools are the right approach. Under Settings → Tools → External Tools you create a new tool: the program is the path to the PHPStan binary (for a Composer install, $ProjectFileDir$/vendor/bin/phpstan), and the arguments are analyse --configuration=$ProjectFileDir$/phpstan.neon --error-format=checkstyle $FilePath$. As the working directory you set $ProjectFileDir$. With the checkstyle format, PhpStorm can parse the output directly and display errors as annotations in the editor, once you link the output with the corresponding file filter.

The more elegant solution is a quality tools plugin (for example the official PHPStan plugin from the Marketplace). It reads the phpstan.neon from the project, knows the configured level, and shows errors as you type, without a manual invocation. For Docker-based projects, the PHP interpreter needs to point to the remote interpreter (more on that in section 6), so that PHPStan works against the project configuration inside the container instead of a potentially different local PHP.


# phpstan.neon - configuration for Magento 2 with PHP 8.4
parameters:
    level: 6
    paths:
        - app/code/Mironsoft
    excludePaths:
        - app/code/Mironsoft/*/Test
    # Magento-specific PHPStan extension
    bootstrapFiles:
        - vendor/magento/magento2-base/dev/tests/static/bootstrap.php
    ignoreErrors:
        # Magento magic methods, known false positives
        - '#Call to an undefined method Magento\\Framework\\#'
    checkMissingIterableValueType: false
    reportUnmatchedIgnoredErrors: false

includes:
    - vendor/phpstan/phpstan-strict-rules/rules.neon
    - vendor/bitexpert/phpstan-magento/extension.neon

For everyday use, a two-tier strategy is recommended: a "Fast" profile analyzes only the currently open file ($FilePath$), a "Full" profile analyzes the entire module. Both can be set up as separate external tools and made reachable via keyboard shortcuts. That way the fast feedback loop for the current work stays intact, while a full analysis is available at the press of a button.

3. Configuring the PHPUnit integration and test runner

The PHPUnit integration in PhpStorm is one of the most mature of all native integrations. Under Settings → PHP → Test Frameworks you create a PHPUnit configuration. For Composer-based projects you choose "PHPUnit by Composer autoloader" and provide the path to vendor/autoload.php. The configuration file (phpunit.xml or phpunit.xml.dist) is detected automatically once it sits in the project root. PhpStorm reads the test suites from it and makes them available in the test runner panel.

Once configured, you can start individual tests by clicking the green play icon next to the method, run an entire test suite in the run panel, or use the coverage runner to display code coverage with inline highlighting. For Magento 2 unit tests you need to make sure the autoloader points correctly to the Magento bootstrap and that all necessary bootstrap files are included, because Magento ships its own object factory that PHPUnit does not know about without a bootstrap.


<?xml version="1.0" encoding="UTF-8"?>
<!-- phpunit.xml - Magento 2 unit tests with PhpStorm compatibility -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="dev/tests/unit/framework/bootstrap.php"
         colors="true"
         columns="120"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Mironsoft Unit Tests">
            <directory>app/code/Mironsoft/*/Test/Unit</directory>
        </testsuite>
    </testsuites>
    <coverage>
        <include>
            <directory suffix=".php">app/code/Mironsoft</directory>
        </include>
        <exclude>
            <directory>app/code/Mironsoft/*/Test</directory>
        </exclude>
    </coverage>
    <php>
        <const name="TESTS_CLEANUP" value="disabled"/>
        <const name="MAGENTO_EXTRA_VERBOSE_CONFIG_ARRAY" value="1"/>
    </php>
</phpunit>

4. PHPCS and PHPCBF as an on-save action

PHPCS can be set up in PhpStorm as a native code quality tool: Settings → PHP → Quality Tools → PHP Code Sniffer. There you provide the path to the binary and the ruleset. With "Show warnings as" set to "Error" or "Warning", violations show up directly in the editor as colored markers, without a manual invocation. It is important that the ruleset uses the same standard as CI, otherwise developers fix something locally that CI reports as an error again.

PHPCBF is the automatic counterpart: it fixes every automatically fixable PHPCS violation. Set up as an external tool in PhpStorm, you can apply PHPCBF to the current file with a shortcut. Even more convenient is the integration as a file watcher or as an action under Settings → Tools → Actions on Save. Since PhpStorm 2023 there are dedicated entries there for external tools, so PHPCBF runs automatically after every save, the cursor does not jump, and the file is silently corrected.

5. Rector as an external tool for automatic refactoring

Rector is not a linter, it is an automatic code transformer: it reads PHP code, applies configured rules, and writes the file back. In a CI pipeline, Rector runs in "dry-run" mode and reports what it would change. Locally in PhpStorm you want to run Rector directly, so the transformations become visible immediately. Set up as an external tool: program vendor/bin/rector, arguments process $FilePath$ --config=rector.php, working directory $ProjectFileDir$.

After execution, PhpStorm automatically opens the diff view if you have "Open console" enabled and Rector made changes. Alternatively, the integration works through the git diff panel: Rector changes the file on disk, PhpStorm detects the change, and displays it in the diff. For PHP 8.4 upgrades, constructor property promotion, typed class constants, readonly properties, the corresponding Rector sets are enabled with a few lines in rector.php.


<?php
// rector.php - configuration for PHP 8.4 upgrade and Magento 2
declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnTypeDeclarationRector;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/app/code/Mironsoft',
    ])
    ->withSkip([
        __DIR__ . '/app/code/Mironsoft/*/Test',
    ])
    ->withSets([
        LevelSetList::UP_TO_PHP_84,
        SetList::TYPE_DECLARATION,
        SetList::EARLY_RETURN,
    ])
    ->withRules([
        AddReturnTypeDeclarationRector::class,
        TypedPropertyFromAssignsRector::class,
    ])
    // do not touch Magento generated classes
    ->withSkip([
        '*/generated/*',
        '*/setup/src/*',
    ]);

6. Remote PHP interpreter for Docker setups

For Docker-based development environments like the Mark Shust setup, there are two approaches for quality tools in PhpStorm: use a local PHP interpreter (which may have different extensions) or use the interpreter directly inside the container. The second path is the correct one. Under Settings → PHP you add a new interpreter, choose "From Docker, Vagrant, VM, WSL, Remote" and configure the Docker connection. PhpStorm then connects to the running container and uses its PHP binary and all installed extensions.

This means PHPStan runs with exactly the same PHP version, the same extensions and the same configuration as in CI. PHPCS finds the same dependencies. PHPUnit uses the same autoloader. Parity between local analysis and CI analysis is thereby guaranteed, a common problem in teams where one developer has PHP 8.3 locally but CI runs PHP 8.4 is completely eliminated.

7. Run configurations: everything with a single click

Run configurations in PhpStorm are named, reusable execution plans. You create them under Run → Edit Configurations. For quality gates, compound configurations are a good fit: a single configuration starts PHPStan, then PHPUnit, then PHPCS in sequence and shows all results in their own tab. That way a single click or shortcut is enough to check every quality gate, ideal before a commit or a merge request.

Run configurations can also be checked into the repository as a file (.run/). That means every team member gets the same preconfigured quality gate runs the first time they open the project. New developers do not have to set up anything manually: the PHP interpreter is defined through the Docker configuration, the binaries live in the vendor directory, and the run configuration points to the right paths. Onboarding for the quality gate setup then takes minutes instead of hours.

8. Controlling git hooks from within PhpStorm

Under Settings → Version Control → Git → Commit, PhpStorm offers the option to run actions before the commit: "Run Tests" starts the PHPUnit suite, "Analyze code" runs the configured inspections. This is the IDE-side equivalent of a pre-commit hook. The advantage over a shell hook: you see the result immediately in the commit dialog, can jump straight to the affected spot on error, and can abort the commit or proceed anyway.

For teams that use both PhpStorm and other editors, a combination is recommended: PhpStorm-side pre-commit checks as a convenient interface, plus a bash-based pre-commit hook as a safety net. The hook calls the same binaries (vendor/bin/phpstan analyse, vendor/bin/phpcs), so quality gates still apply even if someone commits from the command line. The configuration in both cases is the same phpstan.neon and .phpcs.xml.

9. Quality gate strategies compared

There are several strategies for enforcing quality gates in a PHP project. The choice depends on team size, CI setup and IDE preferences. The table below shows the main approaches and their trade-offs.

Strategy Feedback time Setup effort Recommendation
CI pipeline only 5 to 15 min Low Only as a fallback, not as the primary gate
Pre-commit hook 30 to 120 sec Medium Solid safety net, no IDE feedback
PhpStorm external tools 2 to 10 sec Medium Fast, but manual invocation
PhpStorm on-save + plugin Instant Higher Best UX, recommended for active development
All layers combined Instant plus safety net Highest Ideal for teams with a mandatory CI gate

The combination of PhpStorm on-save actions for PHPCS/PHPCBF, the PHPStan plugin for real-time analysis, and compound run configurations for the full gate run before a commit is the practically optimal approach. CI remains as the final safety net, but the vast majority of errors never even get committed in the first place.

Mironsoft

PHP code quality, Magento 2 development and DevOps integration

Quality gates that apply before the commit?

We set up PHPStan, PHPUnit, PHPCS and Rector in PhpStorm, with a remote interpreter for Docker, compound run configurations and CI parity, so errors are visible before you push.

PHPStan setup

Level 6+ with the Magento extension, remote interpreter and PhpStorm plugin integration

Rector automation

PHP 8.4 upgrades and code transformations as a one-click action in PhpStorm

CI parity

Keep local and CI configuration in sync, no more "works on my machine"

10. Summary

Bundling PHPStan, PHPUnit, PHPCS and Rector in PhpStorm means shrinking the feedback cycle from minutes to seconds. PHPStan, as a plugin or external tool, shows type errors right in the editor. PHPCS flags style deviations, PHPCBF fixes them automatically on save. PHPUnit runs with a single click as a run configuration, with coverage highlighting directly in the file. Rector transforms code at the press of a button, and the result is immediately visible in the diff.

The key is CI parity: the same phpstan.neon, the same phpunit.xml, the same PHPCS ruleset locally and in the pipeline. With a remote PHP interpreter for Docker-based setups, it is guaranteed that local analysis and CI analysis run on identical prerequisites. That eliminates the most common source of "works locally, fails in CI": differing PHP versions, missing extensions, and diverging configurations.

Quality gates locally in PhpStorm, the essentials at a glance

PHPStan & PHPCS

Plugin or external tool, errors show up in the editor immediately. PHPCS via an on-save action: violations are fixed automatically before they get committed.

PHPUnit integration

Native test runner in PhpStorm, individual tests via icon, coverage with inline highlighting. Configure it once, available to every team member.

Rector as a refactoring tool

External tool for automatic code transformations. PHP 8.4 upgrades with a single keystroke. Result visible immediately in the git diff.

Remote interpreter & CI parity

Use the Docker interpreter in PhpStorm, identical PHP version and extensions as CI. Compound run configurations for a full gate run before the commit.

11. FAQ: Quality gates locally in PhpStorm

1Can PhpStorm display PHPStan natively without a plugin?
Yes, via external tools with a checkstyle output filter. The plugin shows errors right as you type in the editor though, much more convenient than a manual invocation.
2Why a remote interpreter instead of local PHP?
Identical PHP version and extensions as in CI. Discrepancies between local PHP and CI PHP are eliminated, no more "works locally, fails in CI".
3Setting up PHPCBF as an on-save action?
Settings, Tools, Actions on Save: enable the PHPCBF external tool. After every save the current file is formatted automatically, with under a second of latency.
4Sharing run configurations with the team?
Check .run/*.xml into the repository. PhpStorm reads them automatically, every team member has the same quality gate configurations without any manual setup.
5Rector without dry-run, actually applying changes?
Leave out --dry-run in the external tool. Rector writes directly back, PhpStorm shows the changes in the git diff.
6Rector must not touch generated Magento classes?
Configure withSkip(['generated/', 'setup/src/', 'var/generation/']) in rector.php. Never change auto-generated classes manually or through a tool.
7Which PHPStan level for Magento 2?
Level 5 to 6 with bitexpert/phpstan-magento. Level 8+ produces too many false positives from Magento magic methods. With ignoreErrors rules, level 6 can be maintained well.
8PHPUnit coverage possible without Xdebug?
Yes, with pcov or PHPDBG. pcov is significantly faster than Xdebug for pure coverage measurement without debugging overhead.
9Multiple quality tools in one compound run?
Run, Edit Configurations, Compound. Add PHPStan, PHPUnit and PHPCS as individual entries. One click starts all of them in sequence, each result in its own tab.
10Do on-save actions slow down saving?
PHPCBF on the current file is under a second. PHPStan on the entire codebase as an on-save action is too slow, better used as an external tool on demand.