PHPackages                             symplify/phpstan-rules - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. symplify/phpstan-rules

ActivePhpstan-extension[Testing &amp; Quality](/categories/testing)

symplify/phpstan-rules
======================

Set of Symplify rules, type extensions and error formatter for PHPStan

14.12.0(2w ago)26812.7M↓32.9%3020MITPHPPHP ^8.4CI passing

Since Nov 14Pushed 2w ago3 watchersCompare

[ Source](https://github.com/symplify/phpstan-rules)[ Packagist](https://packagist.org/packages/symplify/phpstan-rules)[ Fund](https://www.paypal.me/rectorphp)[ GitHub Sponsors](https://github.com/tomasvotruba)[ RSS](/packages/symplify-phpstan-rules/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (6)Dependencies (22)Versions (466)Used By (20)

PHPStan Rules
=============

[](#phpstan-rules)

[![Downloads](https://camo.githubusercontent.com/b3f99bbd887cb8bb5760faffb13282f5c503d4a7b32b5a0940f674c97eaa8917/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73796d706c6966792f7068707374616e2d72756c65732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/symplify/phpstan-rules/stats)

Set of 80+ PHPStan fun and practical rules that check:

- clean architecture, logical errors,
- naming, class namespace locations
- accidental visibility override,
- and Symfony, Doctrine or PHPUnit best proven practices.

Useful for any type of PHP project, from legacy to modern stack.

Install
-------

[](#install)

```
composer require symplify/phpstan-rules --dev
```

*Note: Make sure you use [`phpstan/extension-installer`](https://github.com/phpstan/extension-installer#usage) to load necessary service configs.*

Usage
-----

[](#usage)

Configuration should be added to your `phpstan.neon` file.

Once you have most rules applied, it's best practice to include whole sets:

```
includes:
    - vendor/symplify/phpstan-rules/config/code-complexity-rules.neon
    - vendor/symplify/phpstan-rules/config/configurable-rules.neon
    - vendor/symplify/phpstan-rules/config/naming-rules.neon
    - vendor/symplify/phpstan-rules/config/static-rules.neon

    # project specific
    - vendor/symplify/phpstan-rules/config/doctrine-rules.neon
    - vendor/symplify/phpstan-rules/config/symfony-rules.neon

    # special set for PHP configs
    - vendor/symplify/phpstan-rules/config/symfony-config-rules.neon
```

### Symfony/Laravel container `->get()`/`->make()` return type extensions

[](#symfonylaravel-container--get-make-return-type-extensions)

Want sharper type inference? The return type extensions are **disabled by default** — enable the ones that fit your stack:

```
parameters:
    symplify:
        symfonyReturnType: true
        laravelReturnType: true
        pathStrings: true
```

- `symfonyReturnType` resolves
    - `$container->get(SomeService::class)` to `SomeService` and
    - Symfony Finder's `$splFileInfo->getRealPath()` to `string`

```
$service = $container->get(SomeService::class);
// $service is now known as SomeService, instead of plain object
```

- `laravelReturnType` does the same for Laravel's `$container->make(SomeService::class)`
- `pathStrings` narrows `getcwd()`, `dirname()` and `realpath()` to `string`:

But at start, make baby steps with one rule at a time:

Jump to: [Symfony-specific rules](#3-symfony-specific-rules), [Doctrine-specific rules](#2-doctrine-specific-rules), [PHPUnit-specific rules](#4-phpunit-specific-rules) or [PHPUnit mock rules](#5-phpunit-mock-rules).

Special rules
-------------

[](#special-rules)

### NewOverSettersRule

[](#newoversettersrule)

If a class is always created with the same set of setters, pass the values via constructor instead. It makes the object state explicit, safer and easier to test:

```
$human = new Human();
$human->setName('Tomas');
$human->setAge(35);
```

❌

```
$human = new Human(name: 'Tomas', age: 35);
```

👍

Both `set*` and `add*` method prefixes are treated as setters. The rule is intentionally conservative — it only reports a class instantiated **at least twice** with the same set of setters each time. It skips Doctrine entities, Symfony `Kernel` subclasses, vendor code and `new` + setters blocks interrupted by a `return` or `throw`.

This rule is disabled by default. Enable it with the `ctor` parameter:

```
parameters:
    symplify:
        ctor: true
```

### ParamNameToTypeConventionRule

[](#paramnametotypeconventionrule)

By convention, we can define parameter type by its name. If we know the "userId" is always an `int`, PHPStan can warn us about it and let us know to fill the type.

```
services:
    -
        class: Symplify\PHPStanRules\Rules\Convention\ParamNameToTypeConventionRule
        tags: [phpstan.rules.rule]
        arguments:
            paramNamesToTypes:
                userId: int
```

```
function run($userId)
{
}
```

❌

```
function run(int $userId)
{
}
```

👍

### CheckRequiredInterfaceInContractNamespaceRule

[](#checkrequiredinterfaceincontractnamespacerule)

Interface must be located in "Contract" or "Contracts" namespace

```
rules:
    - Symplify\PHPStanRules\Rules\CheckRequiredInterfaceInContractNamespaceRule
```

```
namespace App\Repository;

interface ProductRepositoryInterface
{
}
```

❌

```
namespace App\Contract\Repository;

interface ProductRepositoryInterface
{
}
```

👍

### ClassNameRespectsParentSuffixRule

[](#classnamerespectsparentsuffixrule)

Class should have suffix "%s" to respect parent type

🔧 **configure it!**

```
services:
    -
        class: Symplify\PHPStanRules\Rules\ClassNameRespectsParentSuffixRule
        tags: [phpstan.rules.rule]
        arguments:
            parentClasses:
                - Symfony\Component\Console\Command\Command
```

↓

```
class Some extends Command
{
}
```

❌

```
class SomeCommand extends Command
{
}
```

👍

### StringFileAbsolutePathExistsRule

[](#stringfileabsolutepathexistsrule)

Absolute file path must exist. Checked suffixes are "yaml", "yml", "sql", "php" and "json".

```
rules:
    - Symplify\PHPStanRules\Rules\StringFileAbsolutePathExistsRule
```

```
// missing file path
return __DIR__  . '/some_file.yml';
```

❌

```
// correct file path
return __DIR__  . '/../fixtures/some_file.yml';
```

👍

### NoArrayMapWithArrayCallableRule

[](#noarraymapwitharraycallablerule)

Array map with array callable is not allowed. Use anonymous/arrow function instead, to get better static analysis

```
rules:
    - Symplify\PHPStanRules\Rules\Complexity\NoArrayMapWithArrayCallableRule
```

```
$items = ['apple', 'banana', 'orange'];
$items = array_map(['SomeClass', 'method'], $items);
```

❌

```
$items = ['apple', 'banana', 'orange'];
$items = array_map(function ($item) {
    return $this->method($item);
}, $items);
```

👍

### NoConstructorOverrideRule

[](#noconstructoroverriderule)

Possible \_\_construct() override, this can cause missing dependencies or setup

```
rules:
    - Symplify\PHPStanRules\Rules\Complexity\NoConstructorOverrideRule
```

```
class ParentClass
{
    public function __construct(private string $dependency)
    {
    }
}

class SomeClass extends ParentClass
{
    public function __construct()
    {
    }
}
```

❌

```
final class SomeClass extends ParentClass
{
    public function __construct(private string $dependency)
    {
    }
}
```

👍

### ExplicitClassPrefixSuffixRule

[](#explicitclassprefixsuffixrule)

Interface have suffix of "Interface", trait have "Trait" suffix exclusively

```
rules:
    - Symplify\PHPStanRules\Rules\Explicit\ExplicitClassPrefixSuffixRule
```

```
