Set of PHP_CodeSniffer Sniffs and PHP-CS-Fixer Fixers used by Symplify projects.
They run best with EasyCodingStandard.
composer require symplify/coding-standard --dev
- Rules with π§ are configurable.
services:
Symplify\CodingStandard\Sniffs\Commenting\AnnotationTypeExistsSniff: ~
β
<?php
class SomeClass
{
/**
* @var NonExistingClass
*/
private $property;
}
π
<?php
class SomeClass
{
/**
* @var ExistingClass
*/
private $property;
}
β
<?php
namespace App;
class Finder
{
}
<?php
namespace App\Entity;
class Finder
{
}
π
<?php
namespace App\Entity;
-class Finder
+class EntityFinder
{
}
Do you want skip some classes? Configure it:
# ecs.yml
services:
Symplify\CodingStandard\Sniffs\Architecture\DuplicatedClassShortNameSniff:
allowed_class_names:
- 'Request'
- 'Response'
services:
Symplify\CodingStandard\Fixer\Commenting\ParamReturnAndVarTagMalformsFixer: ~
<?php
/**
- * @param $name string
+ * @param string $name
- * @return int $value
+ * @return int
*/
function someFunction($name)
{
}
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;
# ecs.yml
services:
Symplify\CodingStandard\Fixer\Commenting\RemoveEndOfFunctionCommentFixer: ~
<?php
function someFunction()
{
-} // end of someFunction
+}
# ecs.yml
services:
Symplify\CodingStandard\Fixer\Order\PrivateMethodOrderByUseFixer: ~
β
<?php
class SomeClass
{
public function run()
{
$this->call1();
$this->call2();
}
private function call2()
{
}
private function call1()
{
}
}
π
<?php
class SomeClass
{
public function run()
{
$this->call1();
$this->call2();
}
private function call1()
{
}
private function call2()
{
}
}
Properties are ordered by visibility first, then by complexity.
# ecs.yml
services:
Symplify\CodingStandard\Fixer\Order\PropertyOrderByComplexityFixer: ~
β
<?php
final class SomeFixer
{
/**
* @var string
*/
private $name;
/**
* @var Type
*/
private $service;
/**
* @var int
*/
private $price;
}
π
<?php
final class SomeFixer
{
/**
* @var int
*/
private $price;
/**
* @var string
*/
private $name;
/**
* @var Type
*/
private $service;
}
# ecs.yml
services:
Symplify\CodingStandard\Sniffs\Architecture\PreferredClassSniff:
oldToPreferredClasses:
DateTime: 'Nette\Utils\DateTime'
β
<?php
$dateTime = new DateTime('now');
π
<?php
$dateTime = new Nette\Utils\DateTime('now');
-$friends = [1 => 'Peter', 2 => 'Paul'];
+$friends = [
+ 1 => 'Peter',
+ 2 => 'Paul'
+];
Just like PhpCsFixer\Fixer\Phpdoc\NoEmptyPhpdocFixer
, but this one removes all doc block lines.
-/**
- */
public function someMethod()
{
}
/**
* @param int $value
*
- *
* @return array
*/
public function setCount($value)
{
}
-preg_match('~pattern~', $value);
+preg_match('#pattern#', $value);
-preg_match("~pattern~d", $value);
+preg_match("#pattern#d", $value);
-Nette\Utils\Strings::match($value, '/pattern/');
+Nette\Utils\Strings::match($value, '#pattern#');
Do you want another char than #
? Configure it:
# ecs.yml
services:
Symplify\CodingStandard\Fixer\ControlStructure\PregDelimiterFixer:
delimiter: '_' # default "#"
-require 'vendor/autoload.php';
+require __DIR__.'/vendor/autoload.php';
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) {
}
}
- Are 120 characters too long for you?
- Do you want to break longs lines but not inline short lines or vice versa?
Change it:
# ecs.yml
services:
Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer:
max_line_length: 100 # default: 120
break_long_lines: true # default: true
inline_short_lines: false # default: true
-public function __construct(EntityManagerInterface $eventManager)
+public function __construct(EntityManagerInterface $entityManager)
{
- $this->eventManager = $eventManager;
+ $this->entityManager = $entityManager;
}
This checker ignores few system classes like std*
or Spl*
by default. In case want to skip more classes, you can configure it:
# ecs.yml
services:
Symplify\CodingStandard\Fixer\Naming\PropertyNameMatchingTypeFixer:
extra_skipped_classes:
- 'MyApp*' # accepts anything like fnmatch
try {
-} catch (SomeException $typoException) {
+} catch (SomeException $someException) {
- $typeException->getMessage();
+ $someException->getMessage();
}
# ecs.yml
services:
Symplify\CodingStandard\Fixer\Order\MethodOrderByTypeFixer:
method_order_by_type:
Rector\Contract\Rector\PhpRectorInterface:
- 'getNodeTypes'
- 'refactor'
β
final class SomeRector implements PhpRectorInterface
{
- public function refactor()
+ public function getNodeTypes()
{
- // refactoring
+ return ['SomeType'];
}
-
- public function getNodeTypes()
+ public function refactor(): void
{
- return ['SomeType'];
+ // refactoring
}
}
-$className = 'DateTime';
+$className = DateTime::class;
This checker takes only existing classes by default. In case want to check another code not loaded by local composer, you can configure it:
# ecs.yml
services:
Symplify\CodingStandard\Fixer\Php\ClassStringToClassConstantFixer:
class_must_exist: false # true by default
Do you want to allow some classes to be in string format?
# ecs.yml
services:
Symplify\CodingStandard\Fixer\Php\ClassStringToClassConstantFixer:
allow_classes:
- 'SomeClass'
class SomeClass
{
/**
* @var string[]
*/
- public $apples;
+ public $apples = [];
public function run()
{
foreach ($this->apples as $mac) {
// ...
}
}
}
<?php declare(strict_types=1);
+
namespace SomeNamespace;
Except for Doctrine entities, they cannot be final.
-class SomeClass implements SomeInterface
+final class SomeClass implements SomeInterface
{
}
In case want check this only for specific interfaces, you can configure them:
# ecs.yml
services:
Symplify\CodingStandard\Fixer\Solid\FinalInterfaceFixer:
only_interfaces:
- 'Symfony\Component\EventDispatcher\EventSubscriberInterface'
- 'Nette\Application\IPresenter'
class SomeClass
{
- /** @var int */
+ /**
+ * @var int
+ */
public $count;
}
β
<?php
throw new RuntimeException('...');
π
<?php
throw new FileNotFoundException('...');
# ecs.yml
services:
Symplify\CodingStandard\Sniffs\CleanCode\ForbiddenParentClassSniff:
forbiddenParentClasses:
- 'Doctrine\ORM\EntityRepository'
# again, 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;
}
}
β
<?php
function someFunction(&$var)
{
$var + 1;
}
π
<?php
function someFunction($var)
{
return $var + 1;
}
β
<?php
class SomeClass
{
public static function someFunction()
{
}
}
π
<?php
class SomeClass
{
public function someFunction()
{
}
}
class SomeClass
{
private const EMPATH_LEVEL = 55;
}
π
<?php
class SomeClass
{
/**
* @var int
*/
private const EMPATH_LEVEL = 55;
}
β
<?php
$value = $anotherValue = [];
π
<?php
$value = [];
$anotherValue = [];
β
<?php
return 'Class ' . $oldClass . ' was removed from ' . $file . '. Use ' . self::class . " instead';
π
<?php
return sprintf('Class "%s" was removed from "%s". Use "%s" instead', $oldClass, $file, self::class);
Is 2 .
too strict? Just configure it:
# ecs.yml
services:
Symplify\CodingStandard\Sniffs\ControlStructure\SprintfOverContactSniff:
maxConcatCount: 4 # "3" by default
β
<?php
// $file = new File;
// $directory = new Diretory([$file]);
β
<?php
d($value);
dd($value);
dump($value);
var_dump($value);
β
<?php
class SomeController
{
public function renderEdit(array $data)
{
$database = new Database;
$database->save($data);
}
}
π
<?php
class SomeController
{
public function renderEdit(array $data)
{
$this->database->save($data);
}
}
This checkers ignores by default some classes, see $allowedClasses
property.
In case want to exclude more classes, you can configure it with class or pattern using fnmatch
:
# ecs.yml
services:
Symplify\CodingStandard\Fixer\DependencyInjection\NoClassInstantiationSniff:
extraAllowedClasses:
- 'PhpParser\Node\*'
Doctrine entities are skipped as well. You can disable that by:
# ecs.yml
services:
Symplify\CodingStandard\Fixer\DependencyInjection\NoClassInstantiationSniff:
includeEntities: true
β
<?php
abstract class SomeClass
{
}
π
<?php
abstract class AbstractSomeClass
{
}
β
<?php
class Some extends Command
{
}
π
<?php
class SomeCommand extends Command
{
}
This checker check few names by default. But if you need, you can configure it:
# ecs.yml
services:
Symplify\CodingStandard\Sniffs\Naming\ClassNameSuffixByParentSniff:
parentTypesToSuffixes:
# defaults
- 'Command'
- 'Controller'
- 'Repository'
- 'Presenter'
- 'Request'
- 'Response'
- 'EventSubscriber'
- 'FixerInterface'
- 'Sniff'
- 'Exception'
- 'Handler'
Or keep all defaults values by using extra_parent_types_to_suffixes
:
# ecs.yml
services:
Symplify\CodingStandard\Sniffs\Naming\ClassNameSuffixByParentSniff:
extraParentTypesToSuffixes:
- 'ProviderInterface'
It also covers Interface
suffix as well, e.g EventSubscriber
checks for EventSubscriberInterface
as well.
β
<?php
interface Some
{
}
π
<?php
interface SomeInterface
{
}
β
<?php
trait Some
{
}
π
<?php
trait SomeTrait
{
}
-
class:
Symplify\CodingStandard\Sniffs\DeadCode\UnusedPublicMethodSniff
-
Requires ECS due double run feature, use with
--clear-cache
so all files are included.
β
<?php
class SomeClass
{
public function usedMethod()
{
}
public function unusedMethod()
{
}
}
$someObject = new SomeClass;
$someObject->usedMethod();
π
<?php
class SomeClass
{
public function usedMethod()
{
}
}
$someObject = new SomeClass;
$someObject->usedMethod();
Open an issue or send a pull-request to main repository.