Home PHP Master PHP Code Quality: PHPStan, Rector, Pint & PHP CS Fixer
Intermediate 3 min · July 13, 2026

Master PHP Code Quality: PHPStan, Rector, Pint & PHP CS Fixer

Learn to enforce PHP code quality with PHPStan, Rector, Pint, and PHP CS Fixer.

N
Naren Founder & Principal Engineer

20+ years shipping production PHP systems at scale. Everything here is grounded in real deployments.

Follow
Production
production tested
July 13, 2026
last updated
2,073
articles · all by Naren
Before you start⏱ 15-20 min read
  • Basic knowledge of PHP syntax and OOP.
  • Composer installed for dependency management.
  • A PHP project (version 7.4 or higher recommended).
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • PHPStan Static analysis to find bugs without running code.
  • Rector Automated refactoring and upgrades (e.g., PHP 7.4 to 8.0).
  • Pint Laravel's opinionated PHP CS Fixer wrapper.
  • PHP CS Fixer Enforces PSR-12 and custom coding standards.
✦ Definition~90s read
What is PHP Code Quality?

PHP code quality tools like PHPStan, Rector, Pint, and PHP CS Fixer help you automatically detect bugs, refactor code, and enforce coding standards.

Think of these tools like a team of code inspectors: PHPStan is a detective finding hidden bugs, Rector is a renovation crew updating old code, and Pint/CS Fixer are style enforcers ensuring everyone writes neatly.
Plain-English First

Think of these tools like a team of code inspectors: PHPStan is a detective finding hidden bugs, Rector is a renovation crew updating old code, and Pint/CS Fixer are style enforcers ensuring everyone writes neatly.

In the rush to ship features, code quality often takes a backseat. But technical debt, inconsistent styles, and subtle bugs can slow down your team and lead to production outages. PHP developers now have a powerful arsenal of tools to automate quality checks: PHPStan for static analysis, Rector for automated refactoring, and Pint/CS Fixer for coding standards. This tutorial will guide you through setting up and integrating these tools into your workflow, with real-world examples and debugging strategies. By the end, you'll have a production-ready pipeline that catches errors before they reach users, modernizes legacy code, and enforces a consistent style across your team.

1. Setting Up PHPStan for Static Analysis

PHPStan is a static analysis tool that finds bugs in your code without running it. It understands PHP's type system and can detect issues like calling methods on null, accessing undefined properties, and more. To get started, install it via Composer: composer require --dev phpstan/phpstan. Then create a phpstan.neon configuration file in your project root. Here's a basic setup:

``neon parameters: level: 6 paths: - src ``

Level 6 is a good starting point for most projects. Run PHPStan with vendor/bin/phpstan analyse. You'll likely see errors – that's normal! Use the baseline feature to ignore existing errors and focus on new ones: vendor/bin/phpstan analyse --generate-baseline. This creates a phpstan-baseline.neon file. Over time, fix the baseline errors and increase the level.

phpstan.neonPHP
1
2
3
4
5
6
7
8
9
parameters:
    level: 6
    paths:
        - src
    excludePaths:
        - src/Legacy
    checkMissingIterableValueType: true
    checkGenericClassInNonGenericObjectType: true
💡Start with Level 0
📊 Production Insight
In production, run PHPStan in CI with level max (9) to prevent type-related outages. Use --memory-limit to avoid OOM on large codebases.
🎯 Key Takeaway
PHPStan catches type errors and undefined variables before runtime. Use baselines to manage legacy code.

2. Automating Refactoring with Rector

Rector is a tool that performs automated refactoring of PHP code. It can upgrade your codebase to newer PHP versions, apply coding standards, and even rename methods. Install it via composer require --dev rector/rector. Create a rector.php config file:

```php <?php

use Rector\Config\RectorConfig; use Rector\Set\ValueObject\SetList;

return RectorConfig::configure() ->withPaths([__DIR__ . '/src']) ->withSets([ SetList::PHP_80, SetList::CODE_QUALITY, ]); ```

Run Rector with vendor/bin/rector process src/ --dry-run to see proposed changes. Remove --dry-run to apply them. Rector is powerful but can be aggressive; always review changes in version control.

rector.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\SetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src'])
    ->withSets([
        SetList::PHP_80,
        SetList::CODE_QUALITY,
    ])
    ->withSkip([
        __DIR__ . '/src/Legacy',
    ]);
⚠ Always Dry-Run First
📊 Production Insight
Run Rector in a separate branch and review changes carefully. Some rules may introduce BC breaks; test thoroughly.
🎯 Key Takeaway
Rector automates tedious refactoring tasks, saving hours of manual work. Use it to upgrade PHP versions or enforce code quality rules.

3. Enforcing Coding Standards with PHP CS Fixer

PHP CS Fixer is a tool that automatically fixes PHP coding standards issues. It supports PSR-12 and many other rules. Install it: composer require --dev friendsofphp/php-cs-fixer. Create a .php-cs-fixer.dist.php config:

```php <?php

$finder = PhpCsFixer\Finder::create() ->in(__DIR__ . '/src') ->exclude('vendor');

return (new PhpCsFixer\Config()) ->setRules([ '@PSR12' => true, 'array_syntax' => ['syntax' => 'short'], 'ordered_imports' => true, ]) ->setFinder($finder); ```

Run with vendor/bin/php-cs-fixer fix. Use --dry-run to preview changes. Integrate into your IDE or pre-commit hook.

.php-cs-fixer.dist.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

$finder = PhpCsFixer\Finder::create()
    ->in(__DIR__ . '/src')
    ->exclude('vendor');

return (new PhpCsFixer\Config())
    ->setRules([
        '@PSR12' => true,
        'array_syntax' => ['syntax' => 'short'],
        'ordered_imports' => true,
        'no_unused_imports' => true,
    ])
    ->setFinder($finder);
🔥PSR-12 is the Standard
📊 Production Insight
Run PHP CS Fixer in CI to ensure all code is formatted consistently. Use --diff to see changes in pull requests.
🎯 Key Takeaway
PHP CS Fixer automatically formats code to follow PSR-12 and other rules, reducing style debates.

4. Laravel Pint: A Simpler Alternative

Laravel Pint is an opinionated PHP CS Fixer wrapper built for Laravel projects. It comes pre-configured with Laravel's coding style. Install it: composer require --dev laravel/pint. Run with ./vendor/bin/pint. Pint requires no configuration by default, but you can customize it via a pint.json file:

``json { "preset": "laravel", "rules": { "simplified_null_return": true } } ``

Pint is faster than PHP CS Fixer because it uses a subset of rules. It's ideal for Laravel developers who want a zero-config solution.

pint.jsonPHP
1
2
3
4
5
6
7
{
    "preset": "laravel",
    "rules": {
        "simplified_null_return": true
    }
}
💡Pint vs CS Fixer
📊 Production Insight
Pint is safe to run in CI. It only modifies formatting, not logic. Use --test to check if files are correctly formatted.
🎯 Key Takeaway
Laravel Pint provides a zero-config coding standard fixer tailored for Laravel. It's a great choice for Laravel projects.

5. Integrating Tools into CI/CD Pipeline

To ensure code quality consistently, integrate these tools into your CI/CD pipeline (e.g., GitHub Actions). Here's a sample workflow that runs PHPStan, Rector (dry-run), and Pint (test) on every push:

```yaml name: Code Quality

on: [push]

jobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: '8.2' - run: composer install - run: vendor/bin/phpstan analyse --level=6 --no-progress - run: vendor/bin/rector process src/ --dry-run --no-progress - run: vendor/bin/pint --test ```

This pipeline will fail if any tool finds issues, preventing bad code from being merged.

.github/workflows/code-quality.ymlPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
name: Code Quality

on: [push]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - run: composer install
      - run: vendor/bin/phpstan analyse --level=6 --no-progress
      - run: vendor/bin/rector process src/ --dry-run --no-progress
      - run: vendor/bin/pint --test
🔥CI Integration
📊 Production Insight
Use separate CI jobs for each tool to parallelize. Cache Composer dependencies to speed up runs.
🎯 Key Takeaway
CI integration enforces code quality automatically. Fail the build on errors to maintain standards.

6. Advanced Configuration and Custom Rules

All four tools support advanced customization. For PHPStan, you can create custom rules by implementing PHPStan\Rules\Rule. For Rector, you can write custom rectors. For PHP CS Fixer, you can define custom fixers. Here's an example of a custom PHPStan rule that disallows var_dump:

```php <?php

use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule;

/* @implements Rule<Node\Expr\FuncCall> */ class NoVarDumpRule implements Rule { public function getNodeType(): string { return Node\Expr\FuncCall::class; }

public function processNode(Node $node, Scope $scope): array { if ($node->name instanceof Node\Name && $node->name->toString() === 'var_dump') { return ['Use of var_dump is not allowed. Remove it.']; } return []; } } ```

``neon services: - class: NoVarDumpRule tags: - phpstan.rules.rule ``

This gives you fine-grained control over your codebase.

NoVarDumpRule.phpPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;

/**
 * @implements Rule<Node\Expr\FuncCall>
 */
class NoVarDumpRule implements Rule
{
    public function getNodeType(): string
    {
        return Node\Expr\FuncCall::class;
    }

    public function processNode(Node $node, Scope $scope): array
    {
        if ($node->name instanceof Node\Name && $node->name->toString() === 'var_dump') {
            return ['Use of var_dump is not allowed. Remove it.'];
        }
        return [];
    }
}
⚠ Custom Rules Complexity
📊 Production Insight
Custom rules can be shared across projects via Composer packages. Version them to avoid breaking changes.
🎯 Key Takeaway
Custom rules allow you to enforce project-specific policies. Use them sparingly to avoid maintenance burden.
● Production incidentPOST-MORTEMseverity: high

The Null Coalescing Nightmare: How PHPStan Saved a Deployment

Symptom
Users reported '500 Internal Server Error' during checkout.
Assumption
The developer assumed a variable was always set because it was in a template.
Root cause
A nullable property was accessed without a null check, causing a TypeError in PHP 8.0.
Fix
Added a null coalescing operator and configured PHPStan to enforce strict checks.
Key lesson
  • Always use static analysis to catch type errors before deployment.
  • Don't assume variables are set; use nullable types and null checks.
  • Integrate PHPStan into CI to block merging with errors.
  • Educate team on PHP 8.0+ type strictness.
  • Use PHPStan's bleeding edge rules for maximum safety.
Production debug guideSymptom to Action3 entries
Symptom · 01
PHPStan reports 'Access to an undefined property'
Fix
Check if the property exists or is misspelled. Use @property PHPDoc for magic properties.
Symptom · 02
Rector changes code unexpectedly
Fix
Run Rector with --dry-run first. Review the diff before applying.
Symptom · 03
Pint/CS Fixer breaks formatting
Fix
Check your config file for conflicting rules. Use --diff to see changes.
★ Quick Debug Cheat SheetCommon issues and immediate actions for PHP code quality tools.
PHPStan level 9 errors
Immediate action
Lower level temporarily, then fix iteratively.
Commands
vendor/bin/phpstan analyse --level=5
vendor/bin/phpstan analyse --generate-baseline
Fix now
Add @phpstan-ignore-next-line comments sparingly.
Rector removes type hints+
Immediate action
Check your Rector config for `removeDead*` rules.
Commands
vendor/bin/rector process src/ --dry-run
vendor/bin/rector process src/
Fix now
Disable RemoveUnused* rules if needed.
Pint changes code style unexpectedly+
Immediate action
Review the diff and adjust `.php-cs-fixer.dist.php`.
Commands
vendor/bin/pint --test
vendor/bin/pint --diff
Fix now
Add // pint: ignore comments to skip specific lines.
ToolPurposeConfigurationSpeedBest For
PHPStanStatic analysisphpstan.neonMediumFinding bugs
RectorAutomated refactoringrector.phpSlowUpgrading code
PHP CS FixerCoding standards.php-cs-fixer.dist.phpFastFormatting
Laravel PintCoding standards (Laravel)pint.jsonFastLaravel projects
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
phpstan.neonparameters:1. Setting Up PHPStan for Static Analysis
rector.phpuse Rector\Config\RectorConfig;2. Automating Refactoring with Rector
.php-cs-fixer.dist.php$finder = PhpCsFixer\Finder::create()3. Enforcing Coding Standards with PHP CS Fixer
pint.json{4. Laravel Pint
.githubworkflowscode-quality.ymlname: Code Quality5. Integrating Tools into CI/CD Pipeline
NoVarDumpRule.phpuse PhpParser\Node;6. Advanced Configuration and Custom Rules

Key takeaways

1
PHPStan catches type errors and undefined variables before runtime.
2
Rector automates refactoring and upgrades, saving time.
3
PHP CS Fixer and Pint enforce consistent coding standards.
4
Integrate all tools into CI to maintain quality automatically.
5
Custom rules allow project-specific enforcement but add complexity.

Common mistakes to avoid

4 patterns
×

Running Rector without dry-run first

×

Ignoring PHPStan errors by setting level to 0

×

Using Pint with a custom config that conflicts with Laravel preset

×

Not caching PHPStan results

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is static analysis and how does PHPStan help?
Q02SENIOR
How would you configure Rector to upgrade a codebase from PHP 7.4 to 8.0...
Q03SENIOR
Explain the difference between PHP CS Fixer and Laravel Pint.
Q04SENIOR
How can you create a custom PHPStan rule?
Q01 of 04JUNIOR

What is static analysis and how does PHPStan help?

ANSWER
Static analysis examines code without executing it. PHPStan finds type errors, undefined variables, and other bugs by analyzing the code's abstract syntax tree.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
What is the difference between PHPStan and Psalm?
02
Can I use Rector to upgrade from PHP 7.4 to 8.0?
03
How do I ignore a specific line in PHPStan?
04
Is Pint only for Laravel?
05
How do I speed up PHPStan analysis?
N
Naren Founder & Principal Engineer

20+ years shipping production PHP systems at scale. Everything here is grounded in real deployments.

Follow
Verified
production tested
July 13, 2026
last updated
2,073
articles · all by Naren
🔥

That's Advanced PHP. Mark it forged?

3 min read · try the examples if you haven't

Previous
PSR Standards and PHP-FIG: Writing Interoperable PHP
28 / 29 · Advanced PHP
Next
PHP Package Development with Composer