<!-- This file is generated by ReadmeCommand -->

# PHP CS Fixer: custom fixers

[![CI](https://img.shields.io/github/actions/workflow/status/kubawerlos/php-cs-fixer-custom-fixers/ci.yaml?label=CI)](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/actions/workflows/ci.yaml)
[![Test coverage](https://img.shields.io/codecov/c/gh/kubawerlos/php-cs-fixer-custom-fixers?branch=main&label=Test%20coverage)](https://app.codecov.io/github/kubawerlos/php-cs-fixer-custom-fixers/tree/main)
[![Type coverage](https://img.shields.io/endpoint?label=Type%20coverage&url=https%3A%2F%2Fshepherd.dev%2Fviews%2Fcoverage_data.php%3Fkubawerlos%2Fphp-cs-fixer-custom-fixers)](https://shepherd.dev/github/kubawerlos/php-cs-fixer-custom-fixers)
[![Mutation Score Indicator](https://img.shields.io/endpoint?label=Mutation%20Score%20Indicator&logo=none&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fkubawerlos%2Fphp-cs-fixer-custom-fixers%2Fmain)](https://dashboard.stryker-mutator.io/reports/github.com/kubawerlos/php-cs-fixer-custom-fixers/main)
[![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg?label=Downloads)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers/stats)

A set of custom fixers for [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer).

## Installation
PHP CS Fixer: custom fixers can be installed by running:
```bash
composer require --dev kubawerlos/php-cs-fixer-custom-fixers
```


## Usage
In your PHP CS Fixer configuration register fixers and use them:
```diff
 <?php
 return (new PhpCsFixer\Config())
+    ->registerCustomFixers(new PhpCsFixerCustomFixers\Fixers())
     ->setRules([
         '@PSR2' => true,
         'array_syntax' => ['syntax' => 'short'],
+        PhpCsFixerCustomFixers\Fixer\NoLeadingSlashInGlobalNamespaceFixer::name() => true,
+        PhpCsFixerCustomFixers\Fixer\PhpdocNoSuperfluousParamFixer::name() => true,
     ]);
```
:warning: When PHP CS Fixer is installed via [`php-cs-fixer/shim`](https://github.com/PHP-CS-Fixer/shim) package,
requiring bootstrap may be needed to load `PhpCsFixerCustomFixers` classes:
```php
require __DIR__ . '/vendor/kubawerlos/php-cs-fixer-custom-fixers/bootstrap.php';
```


## Fixers
#### ClassConstantUsageFixer
Class constant must be used instead of a copy of string.
```diff
 <?php
 class Foo
 {
     public const BAR = 'bar';
     public function bar()
     {
-        return 'bar';
+        return self::BAR;
     }
 }
```

#### CommentSurroundedBySpacesFixer
Comments must be surrounded by spaces.
```diff
 <?php
-/*foo*/
+/* foo */
```

#### CommentedOutFunctionFixer
The configured functions must be commented out.
  *Risky: when any of the configured functions have side effects or are overwritten.*
Configuration options:
- `functions` (`array`): list of functions to comment out; defaults to `['print_r', 'var_dump', 'var_export']`
```diff
 <?php
-var_dump($x);
+//var_dump($x);
```

#### ConstructorEmptyBracesFixer
Constructor's empty braces must be on a single line.
```diff
 <?php
 class Foo {
     public function __construct(
         $param1,
         $param2
-    ) {
-    }
+    ) {}
 }
```

#### DataProviderNameFixer
Data provider names must match the name of the test.
  DEPRECATED: use `php_unit_data_provider_name` instead.
  *Risky: when one is calling data provider by name as function.*
Configuration options:
- `prefix` (`string`): prefix that replaces "test"; defaults to `'provide'`
- `suffix` (`string`): suffix to be present at the end; defaults to `'Cases'`
```diff
 <?php
 class FooTest extends TestCase {
     /**
-     * @dataProvider dataProvider
+     * @dataProvider provideSomethingCases
      */
     public function testSomething($expected, $actual) {}
-    public function dataProvider() {}
+    public function provideSomethingCases() {}
 }
```

#### DataProviderReturnTypeFixer
The return type of PHPUnit data provider must be `iterable`.
  DEPRECATED: use `php_unit_data_provider_return_type` instead.
  *Risky: when relying on signature of the data provider.*
```diff
 <?php
 class FooTest extends TestCase {
     /**
      * @dataProvider provideSomethingCases
      */
     public function testSomething($expected, $actual) {}
-    public function provideSomethingCases(): array {}
+    public function provideSomethingCases(): iterable {}
 }
```

#### DataProviderStaticFixer
Data providers must be static.
  DEPRECATED: use `php_unit_data_provider_static` instead.
  *Risky: when one is calling data provider function dynamically.*
Configuration options:
- `force` (`bool`): whether to make the data providers static even if they have a dynamic class call (may introduce fatal error "using $this when not in object context", and you may have to adjust the code manually by converting dynamic calls to static ones); defaults to `false`
```diff
 <?php
 class FooTest extends TestCase {
     /**
      * @dataProvider provideSomethingCases
      */
     public function testSomething($expected, $actual) {}
-    public function provideSomethingCases() {}
+    public static function provideSomethingCases() {}
 }
```

#### DeclareAfterOpeningTagFixer
Declare statement for strict types must be placed on the same line, after the opening tag.
```diff
-<?php
+<?php declare(strict_types=1);
 $foo;
-declare(strict_types=1);
 $bar;
```

#### EmptyFunctionBodyFixer
Empty function body must be abbreviated as `{}` and placed on the same line as the previous symbol, separated with a space.
```diff
 <?php function foo(
     int $x
-)
-{
-}
+) {}
```

#### ForeachUseValueFixer
Value from `foreach` must not be used if possible.
  *Risky: when the value is re-used or being sorted.*
```diff
 <?php
 foreach ($elements as $key => $value) {
-    $product *= $elements[$key];
+    $product *= $value;
 }
```

#### FunctionParameterSeparationFixer
Function parameters, if any is having attribute or hook, must be separated by a blank line.
```diff
 <?php
 class Foo {
     public function __construct(
         #[Attribute1]
         private string $x,
+
         #[Attribute2]
         private string $y,
+
         #[Attribute3]
         private string $z,
     ) {}
 }
```

#### InternalClassCasingFixer
When referencing an internal class it must be written using the correct casing.
  DEPRECATED: use `class_reference_name_casing` instead.
```diff
 <?php
-throw new \exception();
+throw new \Exception();
```

#### IssetToArrayKeyExistsFixer
Function `array_key_exists` must be used instead of `isset` when possible.
  *Risky: when array is not defined, is multi-dimensional or behaviour is relying on the null value.*
```diff
 <?php
-if (isset($array[$key])) {
+if (array_key_exists($key, $array)) {
     echo $array[$key];
 }
```

#### MultilineCommentOpeningClosingAloneFixer
Multiline comments or PHPDocs must contain an opening and closing line with no additional content.
```diff
 <?php
-/** Hello
+/**
+ * Hello
  * World!
  */
```

#### MultilinePromotedPropertiesFixer
Promoted properties must be on separate lines.
  DEPRECATED: use `multiline_promoted_properties` instead.
Configuration options:
- `keep_blank_lines` (`bool`): whether to keep blank lines between properties; defaults to `false`
- `minimum_number_of_parameters` (`int`): minimum number of parameters in the constructor to fix; defaults to `1`
```diff
 <?php
 class Foo {
-    public function __construct(private array $a, private bool $b, private int $i) {}
+    public function __construct(
+        private array $a,
+        private bool $b,
+        private int $i
+    ) {}
 }
```

#### NoCommentedOutCodeFixer
There must be no commented out code.
```diff
 <?php
-//var_dump($_POST);
 print_r($_POST);
```

#### NoDoctrineMigrationsGeneratedCommentFixer
There must be no comments generated by Doctrine Migrations.
```diff
 <?php
 namespace Migrations;
 use Doctrine\DBAL\Schema\Schema;
-/**
- * Auto-generated Migration: Please modify to your needs!
- */
 final class Version20180609123456 extends AbstractMigration
 {
     public function up(Schema $schema)
     {
-        // this up() migration is auto-generated, please modify it to your needs
         $this->addSql("UPDATE t1 SET col1 = col1 + 1");
     }
     public function down(Schema $schema)
     {
-        // this down() migration is auto-generated, please modify it to your needs
         $this->addSql("UPDATE t1 SET col1 = col1 - 1");
     }
 }
```

#### NoDuplicatedArrayKeyFixer
There must be no duplicate array keys.
Configuration options:
- `ignore_expressions` (`bool`): whether to keep duplicated expressions (as they might return different values) or not; defaults to `true`
```diff
 <?php
 $x = [
-    "foo" => 1,
     "bar" => 2,
     "foo" => 3,
 ];
```

#### NoDuplicatedImportsFixer
There must be no duplicate `use` statements.
```diff
 <?php
 namespace FooBar;
 use Foo;
-use Foo;
 use Bar;
```

#### NoImportFromGlobalNamespaceFixer
There must be no imports from the global namespace.
```diff
 <?php
 namespace Foo;
-use DateTime;
 class Bar {
-    public function __construct(DateTime $dateTime) {}
+    public function __construct(\DateTime $dateTime) {}
 }
```

#### NoLeadingSlashInGlobalNamespaceFixer
Classes in the global namespace cannot contain leading slashes.
```diff
 <?php
-$x = new \Foo();
+$x = new Foo();
 namespace Bar;
 $y = new \Baz();
```

#### NoNullableBooleanTypeFixer
There must be no nullable boolean types.
  *Risky: when the null is used.*
```diff
 <?php
-function foo(?bool $bar) : ?bool
+function foo(bool $bar) : bool
 {
      return $bar;
  }
```

#### NoPhpStormGeneratedCommentFixer
There must be no comments generated by PhpStorm.
```diff
 <?php
-/**
- * Created by PhpStorm.
- * User: root
- * Date: 01.01.70
- * Time: 12:00
- */
 namespace Foo;
```

#### NoReferenceInFunctionDefinitionFixer
There must be no parameters passed by reference in functions.
  *Risky: when rely on reference.*
```diff
 <?php
-function foo(&$x) {}
+function foo($x) {}
```

#### NoSuperfluousConcatenationFixer
There must be no superfluous concatenation of literal strings.
Configuration options:
- `allow_preventing_trailing_spaces` (`bool`): whether to keep concatenation if it prevents having trailing spaces in string; defaults to `false`
- `keep_concatenation_for_different_quotes` (`bool`): whether to keep concatenation if single-quoted and double-quoted would be concatenated; defaults to `false`
```diff
 <?php
-echo 'foo' . 'bar';
+echo 'foobar';
```

#### NoTrailingCommaInSinglelineFixer
An element list written on one line cannot contain a trailing comma.
```diff
 <?php
-$x = ['foo', 'bar', ];
+$x = ['foo', 'bar'];
```

#### NoUselessCommentFixer
There must be no useless comments.
```diff
 <?php
 /**
- * Class Foo
  * Class to do something
  */
 class Foo {
     /**
-     * Get bar
      */
     function getBar() {}
 }
```

#### NoUselessDirnameCallFixer
There must be no useless `dirname` calls.
```diff
 <?php
-require dirname(__DIR__) . "/vendor/autoload.php";
+require __DIR__ . "/../vendor/autoload.php";
```

#### NoUselessDoctrineRepositoryCommentFixer
There can be no comments generated by Doctrine ORM.
```diff
 <?php
-/**
- * FooRepository
- *
- * This class was generated by the Doctrine ORM. Add your own custom
- * repository methods below.
- */
 class FooRepository extends EntityRepository {}
```

#### NoUselessParenthesisFixer
There must be no useless parentheses.
```diff
 <?php
-foo(($bar));
+foo($bar);
```

#### NoUselessStrlenFixer
Functions `strlen` and `mb_strlen` must not be compared to 0.
  *Risky: when the function `strlen` is overridden.*
```diff
 <?php
-$isEmpty = strlen($string) === 0;
-$isNotEmpty = strlen($string) > 0;
+$isEmpty = $string === '';
+$isNotEmpty = $string !== '';
```

#### NoUselessWriteVisibilityFixer
There must be no useless write visibility.
```diff
 <?php class Foo {
-    public public(set) $x;
-    public(set) $y;
-    protected protected(set) $z;
+    public $x;
+    public $y;
+    protected $z;
 }
```

#### NumericLiteralSeparatorFixer
Numeric literals must have configured separators.
  DEPRECATED: use `numeric_literal_separator` instead.
Configuration options:
- `binary` (`bool`, `null`): whether add, remove or ignore separators in binary numbers; defaults to `false`
- `decimal` (`bool`, `null`): whether add, remove or ignore separators in decimal numbers; defaults to `false`
- `float` (`bool`, `null`): whether add, remove or ignore separators in float numbers; defaults to `false`
- `hexadecimal` (`bool`, `null`): whether add, remove or ignore separators in hexadecimal numbers; defaults to `false`
- `octal` (`bool`, `null`): whether add, remove or ignore separators in octal numbers; defaults to `false`
```diff
 <?php
-echo 0b01010100_01101000; // binary
-echo 135_798_642; // decimal
-echo 1_234.456_78e-4_321; // float
-echo 0xAE_B0_42_FC; // hexadecimal
-echo 0123_4567; // octal
+echo 0b0101010001101000; // binary
+echo 135798642; // decimal
+echo 1234.45678e-4321; // float
+echo 0xAEB042FC; // hexadecimal
+echo 01234567; // octal
```

#### PhpDocPropertySorterFixer
Sorts @property annotations in PHPDoc blocks alphabetically within groups separated by empty lines.
  DEPRECATED: use `PhpdocPropertySortedFixer` instead.
```diff
 <?php
 /**
- * @property string $zzz
  * @property int $aaa
  * @property bool $mmm
+ * @property string $zzz
  */
 class Foo {}
```

#### PhpUnitAssertArgumentsOrderFixer
PHPUnit assertions must have expected argument before actual one.
  *Risky: when original PHPUnit methods are overwritten.*
```diff
 <?php
 class FooTest extends TestCase {
     public function testFoo() {
-        self::assertSame($value, 10);
+        self::assertSame(10, $value);
     }
 }
```

#### PhpUnitDedicatedAssertFixer
PHPUnit assertions like `assertCount` and `assertInstanceOf` must be used over `assertEquals`/`assertSame`.
  *Risky: when original PHPUnit methods are overwritten.*
```diff
 <?php
 class FooTest extends TestCase {
     public function testFoo() {
-        self::assertSame($size, count($elements));
-        self::assertSame($className, get_class($object));
+        self::assertCount($size, $elements);
+        self::assertInstanceOf($className, $object);
     }
 }
```

#### PhpUnitNoUselessReturnFixer
PHPUnit `fail`, `markTestIncomplete` and `markTestSkipped` functions must not be directly followed by `return`.
  *Risky: when original PHPUnit methods are overwritten.*
```diff
 <?php
 class FooTest extends TestCase {
     public function testFoo() {
         $this->markTestSkipped();
-        return;
     }
 }
```

#### PhpUnitRequiresConstraintFixer
Assertions and attributes for PHP and PHPUnit versions must have explicit version constraint and space after comparison operator.
```diff
 <?php
 class MyTest extends TestCase {
     /**
-     * @requires PHP 8.1
+     * @requires PHP >= 8.1
      */
     public function testFoo() {}
 
     /**
-     * @requires PHP <8.3
+     * @requires PHP < 8.3
      */
     public function testBar() {}
 
-    #[\PHPUnit\Framework\Attributes\RequiresPhpunit('12.0')]
+    #[\PHPUnit\Framework\Attributes\RequiresPhpunit('>= 12.0')]
     public function testBaz() {}
 }
```

#### PhpdocArrayStyleFixer
PHPDoc `array<T>` type must be used instead of `T[]`.
  DEPRECATED: use `phpdoc_array_type` instead.
```diff
 <?php
 /**
- * @param int[] $x
- * @param string[][] $y
+ * @param array<int> $x
+ * @param array<array<string>> $y
  */
```

#### PhpdocNoIncorrectVarAnnotationFixer
The `@var` annotations must be used correctly in code.
```diff
 <?php
-/** @var Foo $foo */
 $bar = new Foo();
```

#### PhpdocNoSuperfluousParamFixer
There must be no superfluous parameters in PHPDoc.
```diff
 <?php
 /**
  * @param bool $b
- * @param int $i
  * @param string $s this is string
- * @param string $s duplicated
  */
 function foo($b, $s) {}
```

#### PhpdocOnlyAllowedAnnotationsFixer
Only the listed annotations are allowed in PHPDoc.
Configuration options:
- `elements` (`array`): list of annotations to keep in PHPDoc; defaults to `[]`
```diff
 <?php
 /**
  * @author John Doe
- * @package foo
- * @subpackage bar
  * @version 1.0
  */
 function foo_bar() {}
```

#### PhpdocParamOrderFixer
Orders all `@param` annotations in DocBlocks according to method signature.
  DEPRECATED: use `phpdoc_param_order` instead.
```diff
 <?php
 /**
  * Annotations in wrong order
  *
  * @param int   $a
+ * @param array $b
  * @param Foo   $c
- * @param array $b
  */
 function m($a, array $b, Foo $c) {}
```

#### PhpdocParamTypeFixer
The `@param` annotations must have a type.
```diff
 <?php
 /**
  * @param string $foo
- * @param        $bar
+ * @param mixed  $bar
  */
 function a($foo, $bar) {}
```

#### PhpdocPropertySortedFixer
Sorts @property annotations in PHPDoc blocks alphabetically within groups separated by empty lines.
```diff
 <?php
 /**
- * @property string $zzz
  * @property int $aaa
  * @property bool $mmm
+ * @property string $zzz
  */
 class Foo {}
```

#### PhpdocSelfAccessorFixer
In PHPDoc, the class or interface element `self` must be used instead of the class name itself.
```diff
 <?php
 class Foo {
     /**
-     * @var Foo
+     * @var self
      */
      private $instance;
 }
```

#### PhpdocSingleLineVarFixer
The `@var` annotation must be on a single line if it is the only content.
```diff
 <?php
 class Foo {
-    /**
-     * @var string
-     */
+    /** @var string */
     private $name;
 }
```

#### PhpdocTagNoNamedArgumentsFixer
There must be `@no-named-arguments` tag in PHPDoc of a class/enum/interface/trait.
  DEPRECATED: use `phpdoc_tag_no_named_arguments` instead.
Configuration options:
- `description` (`string`): description of the tag; defaults to `''`
- `directory` (`string`): directory in which apply the changes, empty value will result with current working directory (result of `getcwd` call); defaults to `''`
```diff
 <?php
+
+/**
+ * @no-named-arguments
+ */
 class Foo
 {
     public function bar(string $s) {}
 }
```

#### PhpdocTypeListFixer
PHPDoc `list` type must be used instead of `array` without a key.
  DEPRECATED: use `phpdoc_list_type` instead.
```diff
 <?php
 /**
- * @param array<int> $x
- * @param array<array<string>> $y
+ * @param list<int> $x
+ * @param list<list<string>> $y
  */
```

#### PhpdocTypesCommaSpacesFixer
PHPDoc types commas must not be preceded by a whitespace, and must be succeeded by a single whitespace or newline.
```diff
-<?php /** @var array<int,string> */
+<?php /** @var array<int, string> */
```

#### PhpdocTypesTrimFixer
PHPDoc types must be trimmed.
```diff
 <?php
 /**
- * @param null | string $x
+ * @param null|string $x
  */
 function foo($x) {}
```

#### PhpdocVarAnnotationToAssertFixer
Converts `@var` annotations to `assert` calls when used in assignments.
```diff
 <?php
-/** @var string $x */
 $x = getValue();
+assert(is_string($x));
```

#### PromotedConstructorPropertyFixer
Constructor properties must be promoted if possible.
Configuration options:
- `promote_only_existing_properties` (`bool`): whether to promote only properties that are defined in class; defaults to `false`
```diff
 <?php
 class Foo {
-    private string $bar;
-    public function __construct(string $bar) {
-        $this->bar = $bar;
+    public function __construct(private string $bar) {
     }
 }
```

#### ReadonlyPromotedPropertiesFixer
Promoted properties must be declared as read-only.
  *Risky: when property is written.*
```diff
 <?php class Foo {
     public function __construct(
-        public array $a,
-        public bool $b,
+        public readonly array $a,
+        public readonly bool $b,
     ) {}
 }
```

#### SingleSpaceAfterStatementFixer
Statements not followed by a semicolon must be followed by a single space.
Configuration options:
- `allow_linebreak` (`bool`): whether to allow statement followed by linebreak; defaults to `false`
```diff
 <?php
-$foo = new    Foo();
-echo$foo->bar();
+$foo = new Foo();
+echo $foo->bar();
```

#### SingleSpaceBeforeStatementFixer
Statements not preceded by a line break must be preceded by a single space.
```diff
 <?php
-$foo =new Foo();
+$foo = new Foo();
```

#### StringableInterfaceFixer
A class that implements the `__toString()` method must explicitly implement the `Stringable` interface.
```diff
 <?php
-class Foo
+class Foo implements \Stringable
 {
    public function __toString()
    {
         return "Foo";
    }
 }
```

#### TrimKeyFixer
The string key of an array or generator must be trimmed and have no double spaces.
```diff
 <?php
 $array = [
-    'option 1 ' => 'v1',
-    'option 2  or 3' => 'v23',
+    'option 1' => 'v1',
+    'option 2 or 3' => 'v23',
 ];
```

#### TypedClassConstantFixer
Class constants must have a type.
```diff
 <?php
 class Foo {
-    public const MAX_VALUE_OF_SOMETHING = 42;
-    public const THE_NAME_OF_SOMEONE = 'John Doe';
+    public const int MAX_VALUE_OF_SOMETHING = 42;
+    public const string THE_NAME_OF_SOMEONE = 'John Doe';
 }
```


## Contributing
Request a feature or report a bug by creating an [issue](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues).

Alternatively, fork the repository, commit your changes, and make sure everything is fine:
```bash
composer verify
```
and submit a pull request.
