5 Useful Rules From Symplify Coding Standard

This post is deprecated since September 2018
Symplify 5.0 was released and with that, many checkers were replaced by better ones.

Checkers 2, 4 and 5 were replaced by SlamCsFixer\FinalInternalClassFixer - class is either final or abstract.

@inject refactoring was replaced by AnnotatedPropertyInjectToConstructorInjectionRector from Rector.

This post was updated on April 2018
Updated with ECS 4.0, Neon to YAML migration and checkers to services migration.

Symplify Coding Standard was born from Zenify, back from the days I was only Nette programmer. It focuses on maintainability and clean architecture. I try to make them simple: each of them does one job.

With over 108 000 downloads I think I should write about 5 of them you can use in your projects today.

I wrote about Object Calisthenics few weeks ago - they are very strict and not very handy if you're beginner in coding standard worlds.

Symplify Coding standard is complete opposite. You can start with 1st checker today and your code will be probably able to handle it. It's combination of 23 sniffs and fixers.

The simplest would be...

1. Array property should have default value [] to prevent undefined array issues

class SomeClass
{
    /**
     * @var string[]
     */
    public $apples;

    public function run()
    {
        foreach ($this->apples as $mac) {
            // ...
        }
    }
}

class SomeClass
{
    /**
     * @var string[]
     */
    public $apples = [];
}

Use it

# easy-coding-standard.yml
services:
    Symplify\CodingStandard\Fixer\Property/ArrayPropertyDefaultValueFixer: ~

2. Final Interface

Once I read When to declare classes final by Marco Pivetta with tl;dr;:

Make your classes always final, if they implement an interface, and no other public methods are defined.

I was working at Lekarna.cz in that time (finally shipped in the beginning of August, congrats guys!) and we used a lot of interfaces and had lots of code reviews. So I made a sniff to save us some work.

class SomeClass implements SomeInterface
{
}

final class SomeClass implements SomeInterface
{
}

Use it

# easy-coding-standard.yml
services:
    Symplify\CodingStandard\Sniffs\Classes\FinalInterfaceSniff: ~

3. Class constant fixer

Are you on PHP 5.5? I hope you're PHP 7.1 already.

Well, since PHP 5.5, you can use ::class constant instead of string.

$className = 'DateTime';

$className = DateTime::class;

Use it

# easy-coding-standard.yml
services:
    Symplify\CodingStandard\Fixer\Php\ClassStringToClassConstantFixer: ~

4. Test should be final

This is lighter version of Final Interface rule. No brainer.

use PHPUnit\Framework\TestCase;

class SomeTest extends TestCase
{
}

use PHPUnit\Framework\TestCase;

final class SomeTest extends TestCase
{
}

Use it

# easy-coding-standard.yml
services:
    Symplify\CodingStandard\Sniffs\PHPUnit\FinalTestCaseSniff: ~

5. Equal Interface

What happens if you implement and interface and add few extra public methods?

Your IDE autocomplete won't work, if you don't type hint the class and not the interface.

David Grudl recently wrote about $template methods suggestion in Nette.

This sniff helps you to avoid such cases:

interface SomeInterface
{
    public function run(): void;
}

final class SomeClass implements SomeInterface
{
    public function run(): void
    {
    }

    public function extra(): void
    {
    }
}

interface SomeInterface
{
    public function run(): void;
}

final class SomeClass implements SomeInterface
{
    public function run(): void
    {
    }
}

Use it

# easy-coding-standard.yml
services:
    Symplify\CodingStandard\Sniffs\Classes\EqualInterfaceImplementationSniff: ~

Experimental Bonus: Refactoring Sniff

@inject annotations in Nette have their use cases, but they are mostly overused and breaking SOLID principles left and right from my consultancy experience.

Putting annotations back to constructor is quite a work, but this Fixer will help you with that.

class SomeClass
{
    /**
     * @inject
     * @var RequiredDependencyClass
     */
    public $requiredDependencyClass;
}

class SomeClass
{
    /**
     * @var RequiredDependencyClass
     */
    private $requiredDependencyClass;

    public function __construct(RequiredDependencyClass $requiredDependencyClass)
    {
        $this->requiredDependencyClass = $requiredDependencyClass;
    }
}

Use it

# easy-coding-standard.yml
services:
    Symplify\CodingStandard\Fixer\DependencyInjection\InjectToConstructorInjectionFixer: ~

Sold? Try them

They are used the best with EasyCodingStandard:

composer require --dev symplify/easy-coding-standard symplify/coding-standard

Check your code:

vendor/bin/ecs check --config vendor/symplify/easy-coding-standard/config/symplify.yml

Fix your code:

vendor/bin/ecs check --config vendor/symplify/easy-coding-standard/config/symplify.yml --fix

Let me know how much errors will you find in the comments. I dare you to get to 0! :)

Rest of the Rules

You can find more rules like Abstract Class, Exception, Trait and Interface naming, indexed array indentation, Controllers with 1 method or invoke and so on in README.

Happy coding!


  Continue Learning


Typo? Fix it, please  and join 49 people who build this website