Updated ECS YAML to PHP configuration since ECS 8.
Since Symplify 7.3, you might notice a few deprecation notices in your coding standards. As Symplify 8 release is synced with Symfony cycle, both will be released at the end of May.
What to do with these deprecations? Why were these sniffs dropped? How to handle upgrades in 1 hour?
When you run ECS with version 7.3+:
vendor/bin/ecs check
You might see such notices right before your code gets checked:
PHP Notice: Sniff "..." is deprecated. Use "..." instead
Symplify 7 used lots of sniffs based on coding standard tokens. In time they were made, they were as good. Tokens are best at spaces, abstract syntax tree is best at logical code structure.
E.g. TraitNameSniff
check name of traits and makes sure the name ends with "Trait":
<?php
// hey, this should be "ProductTrait"
trait Product
{
}
Do you see any spaces or token positions? No, it's just:
So writing this rule in tokens is the wrong tool chosen. Why? With tokens, you need to make sure:
But why waste time on re-inventing the wheel, when we can use a tool that handles tedious work for us? It's better to use abstract syntax tree technology, in this case PHPStan.
That's why all the "AST" sniffs were migrated to PHPStan rules.
So what does it mean? Remove all the rules from ecs.php
and let go?
No, all you need to do is switch to PHPStan rules. It's better working and more reliable since it works with context and not token positions. So at first, you might discover a few new reported errors here and there.
There are 14 deprecated sniffs in total. Don't worry, while it might seem like a considerable number, the replacement is a matter of an hour.
Have you used a full Symplify set?
// ecs.php
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
return function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->import(SetList::SYMPLIFY);
};
Then you won't see any deprecations, because rules were removed from the config for you.
Still, I recommend adding these rules to phpstan.neon
.
These rules were removed:
Symplify\CodingStandard\Sniffs\Naming\AbstractClassNameSniff
Symplify\CodingStandard\Sniffs\Naming\TraitNameSniff
Symplify\CodingStandard\Sniffs\Naming\InterfaceNameSniff
and replaced by:
↓
composer require --dev slam/phpstan-extensions
# phpstan.neon
rules:
- SlamPhpStan\ClassNotationRule
The only sniff rule your coding standard should have... just got better.
The orifinal sniffs were removed:
Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff
Symplify\CodingStandard\Sniffs\CleanCode\ClassCognitiveComplexitySniff
and replaced by more advanced AST in form of PHPStan rules:
↓
# phpstan.neon
includes:
- vendor/symplify/coding-standard/packages/cognitive-complexity/config/cognitive-complexity-rules.neon
# if you use default value, you can skip this section
parameters:
symplify:
max_cognitive_complexity: 10
max_class_cognitive_complexity: 60
Symplify\CodingStandard\Sniffs\Commenting\AnnotationTypeExistsSniff
Just drop it. PHPStan level 0 handles this.
Static functions are best way to slowly create technical dept. But sometimes it's tough to code without them.
So instead of forbidding them:
Symplify\CodingStandard\Sniffs\CleanCode\ForbiddenStaticFunctionSniff
↓
Just be honest about them:
# phpstan.neon
rules:
- Symplify\CodingStandard\Rules\NoClassWithStaticMethodWithoutStaticNameRule
The same way you see a "trait" in a file name and know it's a trait, this rule makes sure that classes with static methods have "static" in its name.
I've been using it for 4 days, and oh, what a shame I feel when I want to use a "Static" "service". It makes me think twice both about the design and consequences.
Even though it's repeated over, again and again, that composition beats inheritance, the PHP code I see is full of it.
Sometimes the only way to promote so-far-the-best practise, is to enforce it.
Symplify\CodingStandard\Sniffs\CleanCode\ForbiddenParentClassSniff
↓
# phpstan.neon
rules:
- Symplify\CodingStandard\Rules\ForbiddenParentClassRule
parameters:
symplify:
forbidden_parent_classes:
- 'Doctrine\ORM\EntityRepository'
Symplify\CodingStandard\Sniffs\Architecture\ExplicitExceptionSniff
↓
# phpstan.neon
rules:
- Symplify\CodingStandard\Rules\NoDefaultExceptionRule
Symplify\CodingStandard\Sniffs\Architecture\PreferredClassSniff
↓
# phpstan.neon
parameters:
symplify:
old_to_preferred_classes:
DateTime: 'Nette\Utils\DateTime'
rules:
- Symplify\CodingStandard\Rules\PreferredClassRule
Symplify\CodingStandard\Sniffs\Architecture\DuplicatedClassShortNameSniff
↓
# phpstan.neon
rules:
- Symplify\CodingStandard\Rules\NoDuplicatedShortClassNameRule
&
ReferenceSymplify\CodingStandard\Sniffs\CleanCode\ForbiddenReferenceSniff
↓
# phpstan.neon
rules:
- Symplify\CodingStandard\Rules\NoReferenceRule
dump()
Function in the CodeSymplify\CodingStandard\Sniffs\Debug\DebugFunctionCallSniff
↓
# phpstan.neon
rules:
- Symplify\CodingStandard\Rules\NoDebugFuncCallRule
Symplify\CodingStandard\Sniffs\Naming\ClassNameSuffixByParentSniff
↓
# phpstan.neon
rules:
- Symplify\CodingStandard\Rules\ClassNameRespectsParentSuffixRule
parameters:
symplify:
parent_classes:
- Rector
And that's it! You've just migrated all deprecated sniffs to PHPStan rules. Upgrade to Symplify 8 will be a piece of cake for you.
In the next post, we'll look on the 2nd half - how to migrate fixers into Rector rules.
Happy coding!
Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors.
I'd really appreciate it!