Dégédé: PHP_CODESNIFFER est idéal pour gérer les espaces et les positions de charbon. Pourtant, ces règles concernent l'architecture et la structure du code. En 2020, il existe un outil qui convient parfaitement à cela - phpstan .
En disant que, la calisthénie des objets a été mise en œuvre en tant que règles PHPSTAN dans un package symplify/phpstan-rules . L'utiliser à la place?
includes:
- vendor/symplify/phpstan-rules/packages/object-calisthenics/config/object-calisthenics-rules.neon
- vendor/symplify/phpstan-rules/packages/object-calisthenics/config/object-calisthenics-services.neon
La calisthénie des objets est un ensemble de règles dans le code orienté objet, qui se concentre sur la maintenabilité, la lisibilité, la testabilité et la compréhensibilité . Nous sommes d'abord pragmatiques - ils sont faciles à utiliser tous ensemble ou un par un.
Lisez le post de William Durand ou vérifiez la présentation de Guilherme Blanco .
composer require object-calisthenics/phpcs-calisthenics-rules --devSi vous savez ce que vous voulez, sautez directement à la règle spécifique:
Dans php_codesniffer
vendor/bin/phpcs src tests -sp
--standard=vendor/object-calisthenics/phpcs-calisthenics-rules/src/ObjectCalisthenics/ruleset.xml
--sniffs=ObjectCalisthenics.Classes.ForbiddenPublicPropertyDans Easycodingstandard
# ecs.yaml
services :
ObjectCalisthenicsSniffsClassesForbiddenPublicPropertySniff : ~alors
vendor/bin/ecs check srcX d'indentation par méthode foreach ( $ sniffGroups as $ sniffGroup ) {
foreach ( $ sniffGroup as $ sniffKey => $ sniffClass ) {
if (! $ sniffClass instanceof Sniff) {
throw new InvalidClassTypeException ;
}
}
}?
foreach ( $ sniffGroups as $ sniffGroup ) {
$ this -> ensureIsAllInstanceOf ( $ sniffGroup , Sniff::class);
}
// ...
private function ensureIsAllInstanceOf ( array $ objects , string $ type )
{
// ...
}Dans php_codesniffer:
vendor/bin/phpcs ... --sniffs=ObjectCalisthenics.Metrics.MaxNestingLevelDans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsMetricsMaxNestingLevelSniff : ~ Dans php_codesniffer:
<? xml version = " 1.0 " ?>
< ruleset name = " my-project " >
< rule ref = " ObjectCalisthenics.Metrics.MaxNestingLevel " >
< properties >
< property name = " maxNestingLevel " value = " 2 " />
</ properties >
</ rule >
</ ruleset >Dans ECS:
services :
ObjectCalisthenicsSniffsMetricsMaxNestingLevelSniff :
maxNestingLevel : 2 if ( $ status === self :: DONE ) {
$ this -> finish ();
} else {
$ this -> advance ();
}?
if ( $ status === self :: DONE ) {
$ this -> finish ();
return ;
}
$ this -> advance ();Dans php_codesniffer:
vendor/bin/phpcs ... --sniffs=ObjectCalisthenics.ControlStructures.NoElseDans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsControlStructuresNoElseSniff : ~-> ) par déclaration $ this -> container -> getBuilder ()-> addDefinition (SniffRunner::class);?
$ containerBuilder = $ this -> getContainerBuilder ();
$ containerBuilder -> addDefinition (SniffRunner::class);Dans php_codesniffer:
vendor/bin/phpcs ... --sniffs=ObjectCalisthenics.CodeAnalysis.OneObjectOperatorPerLineDans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsCodeAnalysisOneObjectOperatorPerLineSniff : ~ Dans php_codesniffer:
<? xml version = " 1.0 " ?>
< ruleset name = " my-project " >
< rule ref = " ObjectCalisthenics.CodeAnalysis.OneObjectOperatorPerLine " >
< properties >
< property name = " variablesHoldingAFluentInterface " type = " array " value = " $queryBuilder,$containerBuilder " />
< property name = " methodsStartingAFluentInterface " type = " array " value = " createQueryBuilder " />
< property name = " methodsEndingAFluentInterface " type = " array " value = " execute,getQuery " />
</ properties >
</ rule >
</ ruleset >Dans ECS:
services :
ObjectCalisthenicsSniffsCodeAnalysisOneObjectOperatorPerLineSniff :
variablesHoldingAFluentInterface : ["$queryBuilder", "$containerBuilder"]
methodsStartingAFluentInterface : ["createQueryBuilder"]
methodsEndingAFluentInterface : ["execute", "getQuery"]Ceci est lié à des noms de classe, de trait, d'interface, de constante, de fonction et de variables.
class EM
{
// ...
}?
class EntityMailer
{
// ...
}Dans php_codesniffer:
vendor/bin/phpcs ... --sniffs=ObjectCalisthenics.NamingConventions.ElementNameMinimalLengthDans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsNamingConventionsElementNameMinimalLengthSniff : ~ Dans php_codesniffer:
<? xml version = " 1.0 " ?>
< ruleset name = " my-project " >
< rule ref = " ObjectCalisthenics.NamingConventions.ElementNameMinimalLength " >
< properties >
< property name = " minLength " value = " 3 " />
< property name = " allowedShortNames " type = " array " value = " i,id,to,up " />
</ properties >
</ rule >
</ ruleset >Dans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsNamingConventionsElementNameMinimalLengthSniff :
minLength : 3
allowedShortNames : ["i", "id", "to", "up"] class SimpleStartupController
{
// 300 lines of code
}?
class SimpleStartupController
{
// 50 lines of code
} class SomeClass
{
public function simpleLogic ()
{
// 30 lines of code
}
}?
class SomeClass
{
public function simpleLogic ()
{
// 10 lines of code
}
} class SomeClass
{
// 20 properties
}?
class SomeClass
{
// 5 properties
} class SomeClass
{
// 20 methods
}?
class SomeClass
{
// 5 methods
}Dans php_codesniffer:
vendor/bin/phpcs ... --sniffs=ObjectCalisthenics.Files.ClassTraitAndInterfaceLength,ObjectCalisthenics.Files.FunctionLength,ObjectCalisthenics.Metrics.MethodPerClassLimit,ObjectCalisthenics.Metrics.PropertyPerClassLimitDans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsFilesClassTraitAndInterfaceLengthSniff : ~
ObjectCalisthenicsSniffsFilesFunctionLengthSniff : ~
ObjectCalisthenicsSniffsMetricsMethodPerClassLimitSniff : ~
ObjectCalisthenicsSniffsMetricsPropertyPerClassLimitSniff : ~ Dans php_codesniffer:
<? xml version = " 1.0 " ?>
< ruleset name = " my-project " >
< rule ref = " ObjectCalisthenics.Files.ClassTraitAndInterfaceLength " >
< properties >
< property name = " maxLength " value = " 200 " />
</ properties >
</ rule >
< rule ref = " ObjectCalisthenics.Files.FunctionLength " >
< properties >
< property name = " maxLength " value = " 20 " />
</ properties >
</ rule >
< rule ref = " ObjectCalisthenics.Metrics.PropertyPerClassLimit " >
< properties >
< property name = " maxCount " value = " 10 " />
</ properties >
</ rule >
< rule ref = " ObjectCalisthenics.Metrics.MethodPerClassLimit " >
< properties >
< property name = " maxCount " value = " 10 " />
</ properties >
</ rule >
</ ruleset >Dans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsFilesClassTraitAndInterfaceLengthSniff :
maxLength : 200
ObjectCalisthenicsSniffsFilesFunctionLengthSniff :
maxLength : 20
ObjectCalisthenicsSniffsMetricsPropertyPerClassLimitSniff :
maxCount : 10
ObjectCalisthenicsSniffsMetricsMethodPerClassLimitSniff :
maxCount : 10Ces règles sont partiellement liées à la conception axée sur le domaine.
class ImmutableBankAccount
{
public $ currency = ' USD ' ; private $ amount ;
public function setAmount ( int $ amount )
{
$ this -> amount = $ amount ;
}
}?
class ImmutableBankAccount
{
private $ currency = ' USD ' ; private $ amount ;
public function withdrawAmount ( int $ withdrawnAmount )
{
$ this -> amount -= $ withdrawnAmount ;
}
}Dans php_codesniffer:
vendor/bin/phpcs ... --sniffs=ObjectCalisthenics.Classes.ForbiddenPublicProperty,ObjectCalisthenics.NamingConventions.NoSetterDans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsClassesForbiddenPublicPropertySniff : ~
ObjectCalisthenicsSniffsNamingConventionsNoSetterSniff : ~ Dans php_codesniffer:
<? xml version = " 1.0 " ?>
< ruleset name = " my-project " >
< rule ref = " ObjectCalisthenics.NamingConventions.NoSetter " >
< properties >
< property name = " allowedClasses " type = " array " value = " *DataObject " />
</ properties >
</ rule >
</ ruleset >Dans ECS:
# ecs.yaml
services :
ObjectCalisthenicsSniffsNamingConventionsNoSetterSniff :
allowedClasses :
- ' *DataObject 'Tout en utilisant dans la pratique, nous avons constaté que ces règles étaient trop strictes, vagues ou même ennuyeuses, plutôt que d'aider à écrire un code plus propre et plus pragmatique. Ils sont également étroitement liés à la conception axée sur le domaine.
3. Enveloppez les types et chaînes primitives - depuis PHP 7, vous pouvez utiliser define(strict_types=1) et des indices de type scalaire. Pour d'autres cas, par exemple le courrier électronique, vous pouvez gérer cela dans votre domaine via des objets de valeur.
4. Utilisez des collections de première classe - cette règle a du sens, mais est trop stricte pour être utile dans la pratique. Même notre code ne l'a pas du tout transmis.
8. N'utilisez pas de classes avec plus de deux variables d'instance - cela dépend du domaine individuel de chaque projet. Cela n'a pas de sens de faire une règle pour cela.
1 caractéristique par PR
Chaque nouvelle fonctionnalité doit être couverte par des tests
Tous les tests et vérifications de style doivent passer
composer complete-checkNous serons alors heureux de fusionner votre fonctionnalité.