This document describes the process and discussions that led to the Coding Style PER. Its goal is to explain the reasons behind each decision.
PSR-12 was accepted in 2019 and since then a number of changes have been made to PHP, most notably recent changes for PHP 8 and PHP 8.1, which have implications for coding style guidelines. Whilst PSR-12 is very comprehensive of PHP functionality that existed at the time of writing, new functionality is very open to interpretation. PSR-12 seeks to provide a set way that both coding style tools can implement, projects can declare adherence to and developers can easily relate on between different projects for these coding style reducing cognitive friction.
PSR-12 was an update for PSR-2 which was created based upon the common practices of the PHP-FIG projects at the time but ultimately this meant it was a compromise of many of the different projects' guidelines. The repercussions of projects changing their coding guidelines to align with PSR-2 (Almost all projects do align with PSR-1, even if it is not explicitly stated) were seen to be too great (losing git history, huge changesets and breaking existing patches/pull requests).
PSR-2 required adopters to reformat large amounts of existing code which stifled adoption. To help alleviate this issue with PSR-12, we have taken a more prescriptive approach and defined the standards for new language features as they are released.
However, it is for a lack of wanting to be dictatorial that we aimed to apply PSR-2 styling, rationale and stances (Described in Section 5, Approaches) in PSR-12 instead of establishing new conventions.
The same approach is applied to the current PER.
This PER shares the same goals as PSR-12.
The intent of this guide is to reduce cognitive friction when scanning code from different authors. It does so by enumerating a shared set of rules and expectations about how to format PHP code. When various authors collaborate across multiple projects, it helps to have one set of guidelines to be used among all those projects. Thus, the benefit of this guide is not in the rules themselves, but in the sharing of those rules.
This PER extends, expands and replaces PSR-12, and is therefore also an extension of PSR-1. With PSR-12 being the base of this PER, a list of differences is provided below to assist with migration, but it should be considered as an independent specification.
This PER will include coding style guidelines related to new functionality added to PHP after the publication of PSR-12. This PER will also include clarifications on the text of PSR-12.
The question of whether to include or replace requirements from PSR-1 was examined by the Working Group. However it was decided to omit any such requirements for further consideration in a subsequent release.
It is not the intention of this PER to add entirely new coding style guidelines. It will also not change anything stipulated in PSR-1 and PSR-12.
New releases of this PER are assigned version numbers in keeping with semantic versioning. Semantic versioning is well defined when applied to software releases but has no common definition in other contexts. This PER applies the following meanings:
- Patch versions may contain:
- Any changes that do not alter the underlying requirements of this PER, such as fixing typos, adding clarifications or other modifications with no compatibility impact.
- Minor versions may additionally:
- Add new requirements for PHP syntax previously unspecified in this PER.
- Add, remove or alter requirements in a way that is both more permissive and backwards compatible for implementers.
- Major versions may additionally:
- Add, remove or alter any requirements.
Projects are expected to pin their own coding style guidelines to a major version of this PER, allowing for regular upgrades to minor and patch releases as they are published. When performing such upgrades, it is intended that no change to existing code is required to maintain compliance with all requirements and recommendations of this PER. This ensures new code contributions processed by an automatic formatter follow (or disregard) recommendations consistently with the existing code.
Please note this backwards compatibility promise does not extend to projects that use new PHP syntax yet to be specified in this PER. In this circumstance, a minor version may introduce new requirements that are effectively breaking changes.
It is ultimately determined whether a meaningful change may be included in a minor release on a case-by-case basis by
consensus. The addition of MAY
or OPTIONAL
requirements or the removal of requirements with non-optional RFC 2119
keywords will not always meet the criteria for minor release. For example, specifying that projects may use tabs instead
of spaces for indentation creates a new implicit requirement that projects must use one style consistently; this new
burden on projects to reformat incoming contributions to their chosen style defines the change as major.
The overarching approach is to attempt to apply existing PSR-12 styling and rationale to new functionality as opposed to establishing new conventions.
There was a discussion about whether strict types should be enforced in the standard cs-extended/fig-standards#7. All were in agreement we should only use a MUST or MUST NOT statement and avoid the use of a SHOULD statement and nobody wanted to say that strict types could not be declared. The discussion was whether it should be considered a coding style item which should be covered or whether it was out of scope, and it was decided to be out of scope of a coding style guide.
Numerous options were suggested, and they can be seen here for return type declarations or here for finally blocks and the current implementation was chosen due to consistency with other parts of the standard.
PHP 7.0 introduced scalar types declaration which does not support long type aliases. Therefore, it makes sense to enforce primary short type forms to be used to have uniform syntax and prevent possible confusion.
In order to settle things using data, survey was conducted and responses from 142 people including 17 project representatives were gathered:
Representative | Project | Compound namespaces with a depth of two or more MUST not be used | Header statement grouping and ordering | Declare statements must each be on their own line | Declare statements in PHP files containing markup | Declare statements have no spaces: declare(strict_types=1); |
Block declare statement formatting | new keyword usage, parenthesis required |
Return type declaration formatting | Use statement leading slashes disallowed | Block namespace declaration formatting | General operator spacing | Try, Catch, Finally formatting | Anonymous class declaration formatting | Keyword casing, only lower case | Type keywords, short form only |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Alexander Makarov | Yii framework | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Korvin Szanto | concrete5 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Leo Feyer | Contao | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Larry Garfield | Drupal | ✓ | ✓ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ❌ | ✓ | ✓ |
André R. | eZ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Jan Schneider | Horde | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Karsten Dambekalns | Neos and Flow | ✓ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Andres Gutierrez | Phalcon | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Ryan Thompson | PyroCMS | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ❌ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ |
Matteo Beccati | Revive Adserver | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ |
Damian Mooyman | SilverStripe | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Brian Retterer | Stormpath PHP SDK | ✓ | ✓ | ✓ | ❌ | ❌ | ✓ | ❌ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ❌ | ❌ |
Matthew Weier O'Phinney | Zend Framework | ❌ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Jordi Boggiano | Composer | ❌ | ❌ | ❌ | ✓ | ✓ | ✓ | ❌ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Ben Marks | Magento | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Chuck Burgess | PEAR | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Totals: | 13/3 | 15/1 | 15/1 | 13/3 | 14/2 | 15/1 | 14/2 | 15/1 | 14/2 | 14/2 | 15/1 | 16/0 | 15/1 | 15/1 | 15/1 |
Question | For | Against | Percentage For |
---|---|---|---|
Compound namespaces required depth | 114 | 12 | 89.47% |
Header statement grouping and ordering | 113 | 13 | 88.5% |
Declare statements must each be on their own line | 120 | 6 | 95% |
Declare statements in PHP files containing markup | 119 | 7 | 94.12% |
Declare statements have no spaces | 116 | 10 | 91.38% |
Block declare statement formatting | 118 | 8 | 93.22% |
new keyword usage, parenthesis required |
116 | 10 | 91.38% |
Return type declaration formatting | 115 | 11 | 90.43% |
Use statement leading slashes disallowed | 118 | 8 | 93.22% |
Block namespace declaration formatting | 120 | 6 | 95% |
General operator spacing | 123 | 3 | 97.56% |
Try, Catch, Finally formatting | 124 | 2 | 98.39% |
Anonymous class declaration formatting | 117 | 9 | 92.31% |
Keyword casing, only lower case | 124 | 2 | 98.39% |
Type keywords, short form only | 121 | 5 | 95.87% |
A potential readability issue was raised on the mailing list. We reviewed options for changes to the specification that could provide better readability and the floated option was to require a blank line after the opening bracket of a function if the arguments and the return are both multiline. Instead, it was pointed out that this specification already allows you to decide where you'd like to add blank lines, and so we will leave it to the implementors to decide.
Please note this changelog is not a verbose list of changes from PSR-12 and further but highlights the most notable changes. It should be considered a new specification, and therefore you should read the specification for a full understanding of its contents.
- Lowercase for all keywords - Section 2.5
- Short form for all type keywords - Section 2.5
- Use statement grouping - Section 3
- Use statement blocks - Section 3
- Declare statement/Strict types declaration usage - Section 3
- Parentheses are always required for class instantiation - Section 4
- Typed properties - Section 4.3
- Return type declarations - Section 4.5
- Variadic and reference argument operators - Section 4.5
- Type hints - Section 4.5
- Add finally block - Section 5.6
- Operators - Section 6
- Unary operators - Section 6.1
- Binary operators - Section 6.2
- Ternary operators - Section 6.3
- Anonymous classes - Section 8
- Adjust 'methods' to 'methods and functions' in a number of instances - Throughout
- Adjust references to classes and interfaces to also include traits - Throughout
- StudlyCaps meaning clarified as PascalCase - Section 2.1
- The last line should not be blank but contain an EOL character - Section 2.2
- Blank lines may be added for readability except where explicitly forbidden within the PSR - Section 2.3
- PSR-2 errata statement about multi-line arguments - Section 4
- PSR-2 errata statement about extending multiple interfaces - Section 4
- Forbid blank lines before/after closing/opening braces for classes - Section 4
- Larry Garfield
- Chris Tankersley
- Alexander Makarov
- Ken Guest
- Korvin Szanto
- Luke Diggins
- Everyone involved in PSR-1, PSR-2, PSR-12.
Note: Order descending chronologically.