Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions migration-3.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,22 @@ enum Size
private const Huge = self::Large;
}
```

## [Section 11 - Arrays](https://github.com/php-fig/per-coding-style/blob/3.1.0/spec.md#11-arrays)

The opening bracket of a multiline array MUST NOT be placed on its own line.
This rule applies to arrays in all contexts, not only assignments. For example:

```php
<?php

return [
'foo',
'bar',
];

someFunction([
'foo',
'bar',
]);
```
42 changes: 21 additions & 21 deletions spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use const Vendor\Package\{ConstantA, ConstantB, ConstantC};

class Foo extends Bar implements FooInterface
{
public function sampleFunction(int $a, int $b = null): array
public function sampleFunction(int $a, ?int $b = null): array

@samdark samdark Aug 12, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This syntax still works in PHP 8.4, but emits a deprecation notice. Using ?int avoids the notice and follows the specification’s later recommendation for explicit nullable types.

{
if ($a === $b) {
bar();
Expand All @@ -80,7 +80,7 @@ enum Beep: int

public function isOdd(): bool
{
return $this->value() % 2;
return $this->value % 2 !== 0;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backed enum values are exposed through the value property, not a value() method. The explicit comparison also makes the expression produce the declared bool under strict_types=1.

}
}
```
Expand Down Expand Up @@ -132,9 +132,9 @@ Any new types and keywords added to future PHP versions MUST be in lower case.
Short form of type keywords MUST be used i.e. `bool` instead of `boolean`,
`int` instead of `integer` etc.

Compound types includes intersection, union, and mixed intersection and union type declarations. PHP requires
that all compound types be structured as an ORed (unioned) series of ANDs (intersections), and that each set of
intersections be encased with parentheses.
Compound types include intersection, union, and mixed intersection and union type declarations. PHP requires
that mixed intersection and union types be structured as an ORed (unioned) series of ANDs (intersections),
and that each intersection in such a union be encased with parentheses.

@samdark samdark Aug 12, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A standalone intersection is written A&B, without parentheses. Parentheses are required only when that intersection is one option in a union, as in A|(B&C). The previous wording incorrectly implied that standalone intersections should also be parenthesized.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically the previous text is correct: A single set of ANDs is still technically ORed with the empty set. However, you're correct that the parens are only meaningful in mixed cases, so we'll go with these revisions.


The union symbol `|` and intersection symbol `&` MUST NOT have a leading or trailing space. The parentheses MUST NOT
have a leading or trailing space.
Expand All @@ -160,7 +160,7 @@ function somethingWithReflection(
|\ReflectionParameter
|\ReflectionProperty $reflect
): object|null {
// ...
// ...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is presented as correctly formatted, so its body should use the mandatory four-space indentation defined in section 2.4.

}

function complex(array|(ArrayAccess&Traversable) $input): ArrayAccess&Traversable
Expand Down Expand Up @@ -255,8 +255,8 @@ When the opening `<?php` tag is on the first line of the file, it MUST be on its
own line with no other statements unless it is a file containing markup outside of PHP
opening and closing tags. The `<?php` tag MUST always be lower case.

Import statements MUST never begin with a leading backslash as they
must always be fully qualified.
Import statements MUST never begin with a leading backslash, as imported names
are always resolved from the namespace root.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An imported name is resolved from the namespace root by PHP; calling it “fully qualified” is potentially confusing because fully qualified names are normally written with a leading backslash.


The following example illustrates a complete list of all blocks:

Expand Down Expand Up @@ -335,8 +335,8 @@ For example:
</html>
```

Declare statements MUST NOT contain any spaces and MUST be exactly `declare(strict_types=1)`
(with an optional semicolon terminator).
Declare statements MUST NOT contain any spaces inside the parentheses. For example:
`declare(strict_types=1)` (with an optional semicolon terminator).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-spaces rule applies to every declare statement. The previous wording made declare(strict_types=1) sound like the only permitted declaration, even though it is just an example of the required formatting; other directives such as declare(ticks=1) are also allowed.


Block declare statements are allowed and MUST be formatted as below. Note position of
braces and spacing:
Expand Down Expand Up @@ -606,8 +606,8 @@ class Point
class Point
{
public function __construct(
public readonly int $x,
public readonly int $y,
public readonly int $x,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructor-promoted parameters are still parameters and therefore use the standard four-space indentation level.

public readonly int $y,
) {}
}
```
Expand Down Expand Up @@ -816,7 +816,7 @@ $foo->bar(
<?php

somefunction($foo, $bar, [
// ...
// ...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The array is a single multiline argument rather than a split argument list, but its contents still need the standard four-space indentation.

], $baz);

$app->get('/hello/{name}', function ($name) use ($app) {
Expand Down Expand Up @@ -1098,7 +1098,7 @@ if (

### 5.2 `switch`, `case`, `match`

A switch structure must follow the rules below:
A switch structure MUST follow the rules below:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BCP 14 preamble gives normative meaning only to uppercase keywords. Since the detailed switch rules are requirements, this introductory MUST should be normative too.


* `case` statements MUST be indented one level from the `switch`.
* The `case` statements line MUST consist only of the `case` keyword, a single space, the case condition (an expression), and a colon.
Expand Down Expand Up @@ -1466,15 +1466,15 @@ $longArgs_noVars = function (
$longerArgument,
$muchLongerArgument,
) {
// ...
// ...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These closure-body comments used three spaces while section 2.4 requires four. The same correction is applied to every example in this group.

};

$noArgs_longVars = function () use (
$longVar1,
$longerVar2,
$muchLongerVar3,
) {
// ...
// ...
};

$longArgs_longVars = function (
Expand All @@ -1486,23 +1486,23 @@ $longArgs_longVars = function (
$longerVar2,
$muchLongerVar3,
) {
// ...
// ...
};

$longArgs_shortVars = function (
$longArgument,
$longerArgument,
$muchLongerArgument,
) use ($var1) {
// ...
// ...
};

$shortArgs_longVars = function ($arg) use (
$longVar1,
$longerVar2,
$muchLongerVar3,
) {
// ...
// ...
};
```

Expand Down Expand Up @@ -1731,8 +1731,8 @@ Array declarations MAY be split across multiple lines, where each subsequent lin
is indented once. When doing so, the first value in the array MUST be on the
next line, and there MUST be only one value per line.

When the array declaration is split across multiple lines, the opening bracket
MUST be placed on the same line as the equals sign. The closing bracket
When an array declaration is split across multiple lines, the opening bracket
MUST NOT be placed on its own line. The closing bracket

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old wording mentioned an equals sign, but multiline arrays can also appear in arguments, return statements, defaults, attributes, and nested expressions. Requiring the opening bracket not to be on its own line makes the rule applicable in every context.

MUST be placed on the next line after the last value. There MUST NOT be more
than one value assignment per line. Value assignments MAY use a single line
or multiple lines.
Expand Down