Browse Source

OrderedClassElementsFixer - PHP8.1 readonly properties support

SpacePossum 3 years ago
parent
commit
3454624695

+ 1 - 1
doc/rules/class_notation/ordered_class_elements.rst

@@ -12,7 +12,7 @@ Configuration
 
 List of strings defining order of elements.
 
-Allowed values: a subset of ``['use_trait', 'public', 'protected', 'private', 'constant', 'constant_public', 'constant_protected', 'constant_private', 'property', 'property_static', 'property_public', 'property_protected', 'property_private', 'property_public_static', 'property_protected_static', 'property_private_static', 'method', 'method_abstract', 'method_static', 'method_public', 'method_protected', 'method_private', 'method_public_abstract', 'method_protected_abstract', 'method_public_abstract_static', 'method_protected_abstract_static', 'method_public_static', 'method_protected_static', 'method_private_static', 'construct', 'destruct', 'magic', 'phpunit']``
+Allowed values: a subset of ``['use_trait', 'public', 'protected', 'private', 'constant', 'constant_public', 'constant_protected', 'constant_private', 'property', 'property_static', 'property_public', 'property_protected', 'property_private', 'property_public_readonly', 'property_protected_readonly', 'property_private_readonly', 'property_public_static', 'property_protected_static', 'property_private_static', 'method', 'method_abstract', 'method_static', 'method_public', 'method_protected', 'method_private', 'method_public_abstract', 'method_protected_abstract', 'method_public_abstract_static', 'method_protected_abstract_static', 'method_public_static', 'method_protected_static', 'method_private_static', 'construct', 'destruct', 'magic', 'phpunit']``
 
 Default value: ``['use_trait', 'constant_public', 'constant_protected', 'constant_private', 'property_public', 'property_protected', 'property_private', 'construct', 'destruct', 'magic', 'phpunit', 'method_public', 'method_protected', 'method_private']``
 

+ 11 - 0
src/Fixer/ClassNotation/OrderedClassElementsFixer.php

@@ -60,6 +60,9 @@ final class OrderedClassElementsFixer extends AbstractFixer implements Configura
         'property_public' => ['property', 'public'],
         'property_protected' => ['property', 'protected'],
         'property_private' => ['property', 'private'],
+        'property_public_readonly' => ['property_readonly', 'property_public'],
+        'property_protected_readonly' => ['property_readonly', 'property_protected'],
+        'property_private_readonly' => ['property_readonly', 'property_private'],
         'property_public_static' => ['property_static', 'property_public'],
         'property_protected_static' => ['property_static', 'property_protected'],
         'property_private_static' => ['property_static', 'property_private'],
@@ -301,6 +304,7 @@ class Example
                 'visibility' => 'public',
                 'abstract' => false,
                 'static' => false,
+                'readonly' => false,
             ];
 
             for ($i = $startIndex;; ++$i) {
@@ -323,6 +327,10 @@ class Example
                     continue;
                 }
 
+                if (\defined('T_READONLY') && $token->isGivenKind(T_READONLY)) { // @TODO: drop condition when PHP 8.1+ is required
+                    $element['readonly'] = true;
+                }
+
                 if ($token->isGivenKind([T_PROTECTED, T_PRIVATE])) {
                     $element['visibility'] = strtolower($token->getContent());
 
@@ -464,6 +472,9 @@ class Example
                 if ($element['static']) {
                     $type .= '_static';
                 }
+                if ($element['readonly']) {
+                    $type .= '_readonly';
+                }
             }
 
             $element['position'] = $this->typePosition[$type];

+ 46 - 0
tests/Fixer/ClassNotation/OrderedClassElementsFixerTest.php

@@ -1382,4 +1382,50 @@ class TestClass
             }',
         ];
     }
+
+    /**
+     * @dataProvider provideFix81Cases
+     * @requires PHP 8.1
+     */
+    public function testFix81(string $expected, ?string $input = null, ?array $configuration = null): void
+    {
+        if (null !== $configuration) {
+            $this->fixer->configure($configuration);
+        }
+
+        $this->doTest($expected, $input);
+    }
+
+    public function provideFix81Cases(): \Generator
+    {
+        yield [
+            '<?php
+
+class A
+{
+    readonly public string $publicProp0;
+    public readonly string $publicProp1;
+    public string $pubProp2;
+    protected readonly string $protectedProp0;
+    readonly protected string $protectedProp1;
+    readonly private string $privateProp0;
+    private readonly string $privateProp1;
+}
+',
+            '<?php
+
+class A
+{
+    public string $pubProp2;
+    readonly public string $publicProp0;
+    public readonly string $publicProp1;
+    private readonly string $privateProp1;
+    readonly private string $privateProp0;
+    protected readonly string $protectedProp0;
+    readonly protected string $protectedProp1;
+}
+',
+            ['order' => ['property_public_readonly', 'property_public', 'property_protected_readonly', 'property_private_readonly'], 'sort_algorithm' => 'alpha'],
+        ];
+    }
 }