Repository: PHP-CS-Fixer/PHP-CS-Fixer (php)

Issue:
per-cs: add trailing_comma_in_multiline rule
`trailing_comma_in_multiline` (fully or configured) can become part of PER-CS
https://www.php-fig.org/per/coding-style/#26-trailing-commas

Pull request:
feat: Add trailing comma in multiline to PER-CS 2.0
As per https://www.php-fig.org/per/coding-style/#26-trailing-commas

> Numerous PHP constructs allow a sequence of values to be separated by a comma, and the final item may have an optional comma ... If the list is split across multiple lines, then the last item MUST have a trailing comma.

Closes #7664 

Patch:
diff --git a/doc/ruleSets/PER-CS2.0.rst b/doc/ruleSets/PER-CS2.0.rst
index 659010902..2bdc58950 100644
--- a/doc/ruleSets/PER-CS2.0.rst
+++ b/doc/ruleSets/PER-CS2.0.rst
@@ -20,3 +20,7 @@ Rules
 
 - `method_argument_space <./../rules/function_notation/method_argument_space.rst>`_
 - `single_line_empty_body <./../rules/basic/single_line_empty_body.rst>`_
+- `trailing_comma_in_multiline <./../rules/control_structure/trailing_comma_in_multiline.rst>`_ with config:
+
+  ``['after_heredoc' => true, 'elements' => ['arguments', 'arrays', 'match', 'parameters']]``
+
diff --git a/doc/rules/control_structure/trailing_comma_in_multiline.rst b/doc/rules/control_structure/trailing_comma_in_multiline.rst
index e7f661d1f..3966b8bd1 100644
--- a/doc/rules/control_structure/trailing_comma_in_multiline.rst
+++ b/doc/rules/control_structure/trailing_comma_in_multiline.rst
@@ -103,6 +103,18 @@ Rule sets
 
 The rule is part of the following rule sets:
 
+- `@PER <./../../ruleSets/PER.rst>`_ with config:
+
+  ``['after_heredoc' => true, 'elements' => ['arguments', 'arrays', 'match', 'parameters']]``
+
+- `@PER-CS <./../../ruleSets/PER-CS.rst>`_ with config:
+
+  ``['after_heredoc' => true, 'elements' => ['arguments', 'arrays', 'match', 'parameters']]``
+
+- `@PER-CS2.0 <./../../ruleSets/PER-CS2.0.rst>`_ with config:
+
+  ``['after_heredoc' => true, 'elements' => ['arguments', 'arrays', 'match', 'parameters']]``
+
 - `@PHP73Migration <./../../ruleSets/PHP73Migration.rst>`_ with config:
 
   ``['after_heredoc' => true]``
diff --git a/src/RuleSet/Sets/PERCS2x0Set.php b/src/RuleSet/Sets/PERCS2x0Set.php
index a5c28b199..f336050f3 100644
--- a/src/RuleSet/Sets/PERCS2x0Set.php
+++ b/src/RuleSet/Sets/PERCS2x0Set.php
@@ -32,7 +32,7 @@ public function getName(): string
 
     public function getRules(): array
     {
-        return [
+        $rules = [
             '@PER-CS1.0' => true,
             'array_indentation' => true,
             'cast_spaces' => true,
@@ -42,7 +42,18 @@ public function getRules(): array
             ],
             'method_argument_space' => true,
             'single_line_empty_body' => true,
+            'trailing_comma_in_multiline' => [
+                'after_heredoc' => true,
+                'elements' => ['arguments', 'arrays'],
+            ],
         ];
+
+        if (\PHP_VERSION_ID >= 8_00_00) {
+            $rules['trailing_comma_in_multiline']['elements'][] = 'match';
+            $rules['trailing_comma_in_multiline']['elements'][] = 'parameters';
+        }
+
+        return $rules;
     }
 
     public function getDescription(): string


Test patch:
diff --git a/tests/Fixtures/Integration/set/@PER-CS2.0.test-in.php b/tests/Fixtures/Integration/set/@PER-CS2.0.test-in.php
index 396db5f7f..e81bfa74a 100644
--- a/tests/Fixtures/Integration/set/@PER-CS2.0.test-in.php
+++ b/tests/Fixtures/Integration/set/@PER-CS2.0.test-in.php
@@ -49,4 +49,19 @@ class Aaa implements
 'foo2' => 'bar',
 ];
 
+$arrayMultilineWithoutComma = [
+    'foo' => 'bar',
+    'foo2' => 'bar'
+];
+$heredocMultilineWithoutComma = [
+    'foo',
+    <<<EOD
+        bar
+        EOD
+];
+argumentsMultilineWithoutComma(
+    1,
+    2
+);
+
 ?>
diff --git a/tests/Fixtures/Integration/set/@PER-CS2.0.test-out.php b/tests/Fixtures/Integration/set/@PER-CS2.0.test-out.php
index 6f32dfab2..f5b1a27f2 100644
--- a/tests/Fixtures/Integration/set/@PER-CS2.0.test-out.php
+++ b/tests/Fixtures/Integration/set/@PER-CS2.0.test-out.php
@@ -56,3 +56,18 @@ class Aaa implements
     'foo' => 'bar',
     'foo2' => 'bar',
 ];
+
+$arrayMultilineWithoutComma = [
+    'foo' => 'bar',
+    'foo2' => 'bar',
+];
+$heredocMultilineWithoutComma = [
+    'foo',
+    <<<EOD
+        bar
+        EOD,
+];
+argumentsMultilineWithoutComma(
+    1,
+    2,
+);
diff --git a/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test b/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test
new file mode 100644
index 000000000..ac4b42258
--- /dev/null
+++ b/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test
@@ -0,0 +1,6 @@
+--TEST--
+Integration of @PER-CS2.0 [PHP 8.0 version].
+--RULESET--
+{"@PER-CS2.0": true}
+--REQUIREMENTS--
+{"php": 80000}
diff --git a/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test-in.php b/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test-in.php
new file mode 100644
index 000000000..1961c63b1
--- /dev/null
+++ b/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test-in.php
@@ -0,0 +1,10 @@
+<?php
+
+function parametersMultilineWithoutComma(
+    $x,
+    $y
+) {}
+$matchMultilineWithoutComma = match ($a) {
+    1 => 0,
+    2 => 1
+};
diff --git a/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test-out.php b/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test-out.php
new file mode 100644
index 000000000..5ec7c4929
--- /dev/null
+++ b/tests/Fixtures/Integration/set/@PER-CS2.0_php80.test-out.php
@@ -0,0 +1,10 @@
+<?php
+
+function parametersMultilineWithoutComma(
+    $x,
+    $y,
+) {}
+$matchMultilineWithoutComma = match ($a) {
+    1 => 0,
+    2 => 1,
+};