PHP Static Analyzers: PHPStan, Deptrac, Rector Compared

A serious PHP project always ends up accumulating analysis tools: a phpstan.neon file, a .php-cs-fixer.dist.php, a rector.php, sometimes a deptrac.yaml. Each answers a different question, and that is precisely what creates the confusion. Many teams install two tools that overlap and forget the one they would really miss.
This article compares the main PHP static analysis tools, says what each one does and does not do, and proposes a realistic adoption order for a Symfony project.
What we mean by static analysis
A static analyzer reads the source code without running it. It builds a representation of the program, then applies rules to it. Depending on the rules, it looks for three very different things:
- bugs: a call to a nonexistent method, an unhandled
nullvalue, an inconsistent return type; - style: indentation,
useorder, braces, naming conventions; - structure: dependencies between layers, complexity, dead code.
Comparing these tools as if they were competitors is therefore misleading. Most of them do not replace each other, they complement each other.
PHPStan: the bug detector
PHPStan is the reference tool for detecting typing and logic errors. It offers eleven strictness levels, from 0 to 10, which lets you adopt the tool gradually on an existing codebase. We detailed the setup in our PHPStan guide (in French) and what is new in version 2 in the article on PHPStan 2.0 (in French).
Its strengths:
- a baseline that freezes existing errors and blocks only new ones;
- official extensions for Symfony, Doctrine, and PHPUnit, which understand the service container and repositories;
- customizable rules to encode a team's conventions.
parameters:
level: 6
paths:
- src
includes:
- phpstan-baseline.neon
Its limit: it says nothing about style and nothing about architecture. Perfectly typed code can mix Doctrine and business logic without PHPStan complaining.
Psalm: the alternative that overlaps with PHPStan
Psalm plays on the same field as PHPStan. It also offers levels, a baseline, and an annotation system for complex types. It highlights data flow analysis (taint analysis), which is useful for spotting SQL or XSS injections.
In practice, the two tools find very similar errors. Running them together doubles CI time and false positives, for little gain. Our recommendation is to pick one of the two: PHPStan in the vast majority of cases, thanks to its extension ecosystem and its community. Psalm remains relevant if taint analysis is an explicit requirement.
Need support on your project?
Let's talkPHP-CS-Fixer: the end of style debates
PHP-CS-Fixer looks for no bugs. It rewrites the code so that it follows a standard, for example PSR-12 or the @Symfony ruleset. Its value is human: as long as a tool settles the question, nobody comments on indentation in code review anymore.
<?php
$finder = (new PhpCsFixer\Finder())->in(__DIR__ . '/src');
return (new PhpCsFixer\Config())
->setRules(['@Symfony' => true, 'declare_strict_types' => true])
->setFinder($finder);
It runs in --dry-run mode in CI to fail on a deviation, and in fix mode locally or in a pre-commit hook. It complements a team's coding conventions (in French) by making them executable rather than documentary.
Deptrac: the architecture guardrail
Deptrac answers a question that neither PHPStan nor PHP-CS-Fixer asks: is this class allowed to use that other one? You declare layers (Domain, Application, Infrastructure) and the dependencies allowed between them. Deptrac fails as soon as a rule is violated.
deptrac:
paths:
- ./src
layers:
- name: Domain
collectors:
- type: directory
value: src/Domain/.*
- name: Infrastructure
collectors:
- type: directory
value: src/Infrastructure/.*
ruleset:
Domain: ~
Infrastructure:
- Domain
Here, the Domain depends on nothing, and the Infrastructure may depend on the Domain. A use Doctrine\ORM\... slipped into the Domain breaks the build. This is exactly the principle defended in why your Domain should never know about Symfony (in French), and a natural complement to a hexagonal architecture (in French): without automatic checks, boundaries erode within a few months.
Rector: refactoring in place of developers
Rector does not report problems, it fixes them. It applies code transformation rules: PHP version upgrades, attribute migrations, replacing deprecated APIs. We cover it in detail in the article dedicated to Rector (in French).
It is the most worthwhile tool during a version upgrade, because it turns hundreds of mechanical changes into a single diff review. It is also useful for tackling technical debt (in French) at an industrial scale rather than by hand. A word of caution: always run it on a clean branch, with the tests green before and after.
PHPMD, PHPMetrics, and the others
A few tools complete the picture:
- PHPMD spots signs of poor design: methods that are too long, too many parameters, high cyclomatic complexity. Its rules partly overlap with the higher PHPStan levels and with code review.
- PHPMetrics produces a visual maintainability report. It is used to make a diagnosis during an audit, less to block a CI.
- Infection measures the quality of your tests through mutation testing, which is a different topic from static analysis but is installed the same way.
To track down what is no longer called, dead code analyzers are part of the approach described in our project retrospective on dead code elimination (in French).
Comparison table
| Tool | Detects | Fixes on its own | Adoption |
|---|---|---|---|
| PHPStan | Bugs, types | No | Gradual, by levels |
| Psalm | Bugs, types, taint | Partially | Gradual |
| PHP-CS-Fixer | Style deviations | Yes | Immediate |
| Deptrac | Architecture violations | No | After defining the layers |
| Rector | Code to modernize | Yes | In batches of rules |
| PHPMD | Complexity, design | No | Optional |
In which order to install them
On an existing project, a simple order limits friction:
- PHPStan at a low level with a baseline. The gain is immediate and no developer is blocked. You go up one level per sprint.
- PHP-CS-Fixer. A single reformatting pass, then the CI keeps the style clean. Make this commit on its own so it does not pollute the history.
- Rector, occasionally. Run it at each PHP or Symfony version upgrade, not continuously.
- Deptrac, once the layers are decided. There is no point installing it before the team has agreed on the target architecture.
In a CI, the first three fit in a few lines and run in parallel. What matters most is not the number of tools but that they are blocking: a warning that nobody reads has no value.
Key takeaways
There is no single best PHP static analyzer, because these tools do not answer the same question. PHPStan hunts for bugs, PHP-CS-Fixer settles style, Deptrac protects architecture, Rector modernizes. Choose one tool per question, make them blocking in CI, and raise the level of strictness gradually.
If you want an outside opinion on the quality pipeline of an existing Symfony project, it is a point we systematically examine during a code audit (in French).
Have a project in mind?
Our team replies within 48 hours to look at your needs and suggest a suitable approach.
Contact usFrequently asked questions
PHPStan analyzes type consistency and detects bugs without running the code. PHP-CS-Fixer checks no logic: it reformats the code to apply a style standard like PSR-12. The two are complementary and both run in continuous integration.
On a single project, one of the two is enough. Both detect very similar families of errors. PHPStan now has the largest community and extension ecosystem, notably for Symfony and Doctrine, which makes it the default choice for most teams.
Deptrac checks architecture rules: which layer is allowed to call which other layer. PHPStan checks that the code is properly typed, not that the domain stays independent of the framework. Deptrac fails the CI if a forbidden dependency appears.
Start with PHPStan at a low level with a baseline, then PHP-CS-Fixer to remove style noise from reviews. Add Rector to automate version upgrades, and Deptrac once the team has defined the layers it wants to protect.
Related articles

RGAA Accessibility Remediation for Symfony Apps
Since the European Accessibility Act, RGAA now covers far more organizations. How we fix a Symfony application: semantic Twig, ARIA, keyboard use and tests.
Read more →
PHPStan Max Level on Symfony: The Top 10 Errors
Raising PHPStan to level 10 on a Symfony project reveals dozens of errors. Here are the 10 most common ones and how to fix them cleanly, without losing sprints.
Read more →
PHP Dead Code: Detect and Remove Unused Code
Find and remove unused code in your PHP projects with PHPStan and shipmonk/dead-code-detector to improve code quality, maintainability and tooling speed.
Read more →