symplify/coding-standard

Set of Symplify rules for PHP_CodeSniffer and PHP CS Fixer.

Fund package maintenance!
tomasvotruba

Installs: 1 687 150

Dependents: 30

Suggesters: 2

Security: 0

Stars: 235

Watchers: 10

Forks: 10

v8.1.19 2020-07-30 20:43 UTC

This package is auto-updated.

Last update: 2020-07-30 20:47:53 UTC


README

Downloads

Set of rules for PHP_CodeSniffer, PHP-CS-Fixer and PHPStan used by Symplify projects.

They run best with EasyCodingStandard and PHPStan.

Install

composer require symplify/coding-standard --dev
composer require symplify/easy-coding-standard --dev
  1. Run with ECS:
vendor/bin/ecs process src --set symplify
  1. Register rules for PHPStan:
# phpstan.neon
includes:
    - vendor/symplify/coding-standard/config/symplify-rules.neon

Rules Overview


Cognitive Complexity for Method and Class Must be Less than X

For PHPStan

# phpstan.neon
includes:
    - vendor/symplify/coding-standard/packages/cognitive-complexity/config/cognitive-complexity-rules.neon

parameters:
    symplify:
        max_cognitive_complexity: 8 # default
        max_class_cognitive_complexity: 50 # default

<?php

class SomeClass
{
    public function simple($value)
    {
        if ($value !== 1) {
            if ($value !== 2) {
                if ($value !== 3) {
                    return false;
                }
            }
        }

        return true;
    }
}

👍

<?php

class SomeClass
{
    public function simple($value)
    {
        if ($value === 1) {
            return true;
        }

        if ($value === 2) {
            return true;
        }

        return $value === 3;
    }
}

Classes with Static Methods must have "Static" in the Name

Be honest about static. Why is static bad?

Value object static constructors, EventSubscriber and Command classe are excluded.

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoClassWithStaticMethodWithoutStaticNameRule

<?php

class FormatConverter // should be: "StaticFormatConverter"
{
    public static function yamlToJson(array $yaml): array
    {
        // ...
    }
}

Remove Extra Spaces around Property and Constants Modifiers

# ecs.yaml
services:
    Symplify\CodingStandard\Fixer\Spacing\RemoveSpacingAroundModifierAndConstFixer: null
 class SomeClass
 {
-    protected     static     $value;
+    protected static $value;
}

Use Unique Class Short Names

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoDuplicatedShortClassNameRule

<?php

namespace App;

class Finder
{
}
<?php

namespace App\Entity;

class Finder // should be e.g. "EntityFinder"
{
}

Make @param, @return and @var Format United

# ecs.yaml
services:
    Symplify\CodingStandard\Fixer\Commenting\ParamReturnAndVarTagMalformsFixer: null
 <?php

 /**
- * @param $name string
+ * @param string $name
  *
- * @return int $value
+ * @return int
  */
 function someFunction($name)
 {
 }
 <?php

 class SomeClass
 {
     /**
-     * @var int $property
+     * @var int
      */
     private $property;
 }
-/* @var int $value */
+/** @var int $value */
 $value = 5;

-/** @var $value int */
+/** @var int $value */
 $value = 5;

Prefer Another Class

# phpstan.neon
parameters:
    symplify:
        old_to_preffered_classes:
            DateTime: 'Nette\Utils\DateTime'

rules:
    - Symplify\CodingStandard\Rules\PreferredClassRule

<?php

$dateTime = new DateTime('now'); // should be "Nette\Utils\DateTime"

Require @see annotation to class Test case by Type

# phpstan.neon
parameters:
    symplify:
        required_see_types:
            - PHPStan\Rules\Rule

rules:
    - Symplify\CodingStandard\Rules\SeeAnnotationToTestRule

<?php

use PHPStan\Rules\Rule;

class SomeRule implements Rule
{
    // ...
}

👍

<?php

use PHPStan\Rules\Rule;

/**
 * @see SomeRuleTest
 */
class SomeRule implements Rule
{
    // ...
}

Defined Method Argument should be Always Constant Value

# phpstan.neon
parameters:
    symplify:
        constant_arg_by_method_by_type:
            AlwaysCallMeWithConstant:
                some_type: [0] # positions

rules:
    - Symplify\CodingStandard\Rules\ForceMethodCallArgumentConstantRule

<?php

class SomeClass
{
    public function run()
    {
        $alwaysCallMeWithConstant = new AlwaysCallMeWithConstant();
        $alwaysCallMeWithConstant->call('someValue');
        // should be: $alwaysCallMeWithConstant->call(TypeList::SOME);

    }
}

Indexed PHP arrays should have 1 item per line

# ecs.yaml
services:
    Symplify\CodingStandard\Fixer\ArrayNotation\StandaloneLineInMultilineArrayFixer: null
-$friends = [1 => 'Peter', 2 => 'Paul'];
+$friends = [
+    1 => 'Peter',
+    2 => 'Paul'
+];

Block comment should not have 2 empty lines in a row

# ecs.yaml
services:
    Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousDocBlockWhitespaceFixer: null
 /**
  * @param int $value
  *
- *
  * @return array
  */
 public function setCount($value)
 {
 }

Parameters, Arguments and Array items should be on the same/standalone line to fit Line Length

# ecs.yaml
services:
    Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer:
        # defaults
        max_line_length: 120
        break_long_lines: true
        inline_short_lines: true
 class SomeClass
 {
-    public function someMethod(SuperLongArguments $superLongArguments, AnotherLongArguments $anotherLongArguments, $oneMore)
+    public function someMethod(
+        SuperLongArguments $superLongArguments,
+        AnotherLongArguments $anotherLongArguments,
+        $oneMore
+    )
     {
     }

-    public function someOtherMethod(
-        ShortArgument $shortArgument,
-        $oneMore
-    ) {
+    public function someOtherMethod(ShortArgument $shortArgument, $oneMore) {
     }
 }

Strict types declaration has to be followed by empty line

# ecs.yaml
services:
    Symplify\CodingStandard\Fixer\Strict\BlankLineAfterStrictTypesFixer: null
 <?php

declare(strict_types=1);
+
 namespace SomeNamespace;

Constant type Must Match its Value

# ecs.yaml
services:
    Symplify\CodingStandard\Rules\MatchingTypeConstantRule: null

<?php

class SomeClass
{
    /**
     * @var int
     */
    private const LIMIT = 'max';
}

👍

<?php

class SomeClass
{
    /**
     * @var string
     */
    private const LIMIT = 'max';
}

Boolish Methods has to have is/has/was Name

# ecs.yaml
services:
    Symplify\CodingStandard\Rules\BoolishClassMethodPrefixRule: null

<?php

class SomeClass
{
    public function old(): bool
    {
        return $this->age > 100;
    }
}

👍

<?php

class SomeClass
{
    public function isOld(): bool
    {
        return $this->age > 100;
    }
}

Forbidden return of require_once()/incude_once()

# ecs.yaml
services:
    Symplify\CodingStandard\Rules\ForbidReturnValueOfIncludeOnceRule: null

<?php

class SomeClass
{
    public function run()
    {
        return require_once 'Test.php';
    }
}

Use custom exceptions instead of Native Ones

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoDefaultExceptionRule

<?php

throw new RuntimeException('...'); // should be e.g. "App\Exception\FileNotFoundException"

Class "%s" inherits from forbidden parent class "%s". Use composition over inheritance instead

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\ForbiddenParentClassRule

parameters:
    symplify:
        forbidden_parent_classes:
            - 'Doctrine\ORM\EntityRepository'
            # you can use fnmatch() pattern
            - '*\AbstractController'

<?php

use Doctrine\ORM\EntityRepository;

final class ProductRepository extends EntityRepository
{
}

👍

<?php

use Doctrine\ORM\EntityRepository;

final class ProductRepository
{
    /**
     * @var EntityRepository
     */
    private $entityRepository;

    public function __construct(EntityRepository $entityRepository)
    {
        $this->entityRepository = $entityRepository;
    }
}

Use explicit return values over magic "&$variable" reference

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoReferenceRule

<?php

function someFunction(&$var)
{
    $var + 1;
}

👍

<?php

function someFunction($var)
{
    return $var + 1;
}

Use explicit Method Names over Dynamic

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoDynamicMethodNameRule

<?php

final class DynamicMethodCallName
{
    public function run($value)
    {
        $this->$value();
    }
}

No isset on objects

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoIssetOnObjectRule

<?php

final class IssetOnObject
{
    public function run()
    {
        if (mt_rand(0, 1)) {
            $object = new SomeClass();
        }

        if (isset($object)) {
            return $object;
        }
    }
}

👍

final class IssetOnObject
{
    public function run()
    {
        $object = null;
        if (mt_rand(0, 1)) {
            $object = new SomeClass();
        }

        if ($object !== null) {
            return $object;
        }
    }
}

No Function Call on Method Call

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoFunctionCallInMethodCallRule

<?php

final class SomeClass
{
    public function run($value): void
    {
        $this->someMethod(strlen('fooo'));
    }

    private function someMethod($value)
    {
        return $value;
    }
}

👍

<?php

final class SomeClass
{
    public function run($value): void
    {
        $fooSize = strlen('fooo');
        $this->someMethod($fooSize);
    }

    private function someMethod($value)
    {
        return $value;
    }
}

Use explicit Property Fetch Names over Dynamic

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoDynamicPropertyFetchNameRule

<?php

final class DynamicPropertyFetchName
{
    public function run($value)
    {
        $this->$value;
    }
}

Use explicit comparison over empty()

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoEmptyRule

<?php

final class SomeClass
{
    public function run($value)
    {
        return empty($value);
    }
}

👍

<?php

final class SomeClass
{
    public function run(array $value)
    {
        return $value === [];
    }
}

There should not be comments with valid code

# ecs.yaml
services:
    Symplify\CodingStandard\Sniffs\Debug\CommentedOutCodeSniff: null

<?php

// $file = new File;
// $directory = new Diretory([$file]);

Debug functions Cannot Be left in the Code

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoDebugFuncCallRule

<?php

d($value);
dd($value);
dump($value);
var_dump($value);

Class should have suffix by parent class/interface

Covers Interface suffix as well, e.g EventSubscriber checks for EventSubscriberInterface as well.

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\ClassNameRespectsParentSuffixRule

parameters:
    symplify:
        parent_classes:
            - Rector
            - Rule

<?php

class Some extends Command // should be "SomeCommand"
{
}

No Parameter can Have Default Value

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoDefaultParameterValueRule

<?php

class SomeClass
{
    public function run($vaulue = true)
    {
    }
}

No Parameter can be Nullable

Inspired by Null Hell by @afilina

# phpstan.neon
rules:
    - Symplify\CodingStandard\Rules\NoNullableParameterRule

<?php

class SomeClass
{
    public function run(?string $vaulue = true)
    {
    }
}

Object Calisthenics rules

No else And elseif

# phpstan.neon
rules:
     - Symplify\CodingStandard\ObjectCalisthenics\Rules\NoElseAndElseIfRule

<?php

if ($value) {
    return 5;
} else {
    return 10;
}

👍

if ($value) {
    return 5;
}

return 10;

No Names Shorter than 3 Chars

# phpstan.neon
rules:
     - Symplify\CodingStandard\ObjectCalisthenics\Rules\NoShortNameRule

<?php

class EM // should be e.g. "EntityManager"
{
}

No setter methods

# phpstan.neon
rules:
     - Symplify\CodingStandard\ObjectCalisthenics\Rules\NoSetterClassMethodRule

<?php

final class Person
{
    private string $name;

    public function setName(string $name) // should be "__construct"
    {
        $this->name = $name;
    }
}

No Chain Method Call

# phpstan.neon
rules:
     - Symplify\CodingStandard\ObjectCalisthenics\Rules\NoChainMethodCallRule

<?php

class SomeClass
{
    public function run()
    {
        return $this->create()->modify()->save();
    }
}

👍

<?php

class SomeClass
{
    public function run()
    {
        $object = $this->create();
        $object->modify();
        $object->save();

        return $object;
    }
}

Contributing

Open an issue or send a pull-request to main repository.