├── README.md ├── migration-3.0.md ├── meta.md ├── migration-2.0.md └── spec.md /README.md: -------------------------------------------------------------------------------- 1 | # PER coding style 2 | 3 | Published version can be found at https://www.php-fig.org/per/coding-style/. 4 | 5 | - [Specification](spec.md) 6 | - [Meta Document](meta.md) 7 | - [Migration Document PER-CS v1.0 to v2.0](migration-2.0.md) 8 | - [Migration Document PER-CS v2.0 to v3.0](migration-3.0.md) 9 | -------------------------------------------------------------------------------- /migration-3.0.md: -------------------------------------------------------------------------------- 1 | # Migrating from PER-CS v2.0 to PER-CS v3.0 ### 2 | 3 | ## Summary 4 | 5 | PER-CS is the next evolution of the PSR set of Coding Standards from the 6 | PHP-FIG (Framework Interoperability Group). It extends the Coding Standards 7 | laid out in PSR-12 to the newest functionality added to PHP such as the match 8 | keyword, enums, attributes, and more. 9 | 10 | This document describes the changes and additions on a section by section 11 | basis between PER-CS v3.0 and PER-CS v2.0. 12 | 13 | It is derived in part from [a GitHub-generated diff](https://github.com/php-fig/per-coding-style/compare/2.0.0...3.0.0#files_bucket) 14 | and focuses on the changes on a section-by-section basis as its focus is to be more readable. 15 | 16 | This document intends to provide a summary of these changes that can 17 | then be used to drive action lists for toolset producers to support PER-CS v3.0. 18 | 19 | This document is non-normative. The published [3.0 PER-CS](https://www.php-fig.org/per/coding-style/) specification 20 | is the canonical source for the PER-CS formatting expectations. 21 | 22 | ## [Section 2.5 - Keywords and Types](https://www.php-fig.org/per/coding-style/#25-keywords-and-types) 23 | 24 | Formatting conventions are now provided for compound types (those that include union or intersection type declarations). 25 | 26 | * The `|` and `&` symbols and parentheses MUST NOT have leading or trailing spaces. 27 | * If a type declaration is long enough to split to multiple lines, each ANDed block must be on one line, and each ORed block on its own line. 28 | * If one of the types listed is `null`, it must come last. 29 | * Favor `?` over `|null` in cases where both work. 30 | * A multi-catch statement must follow the same rules. (See section 5.6 as well.) 31 | 32 | ```php 33 | function foo(int|string $a): User|Product 34 | { 35 | // ... 36 | } 37 | 38 | function complex(array|(ArrayAccess&Traversable) $input): ArrayAccess&Traversable 39 | { 40 | // ... 41 | } 42 | 43 | function veryComplex( 44 | array 45 | |(ArrayAccess&Traversable) 46 | |(Traversable&Countable) $input): ArrayAccess&Traversable 47 | { 48 | // ... 49 | } 50 | ``` 51 | 52 | ## [Section 2.7 - Naming](https://www.php-fig.org/per/coding-style/#27-naming) 53 | 54 | PER-CS now recommends following the same naming conventions as PHP Internals for abbreviations and acronyms. Specifically, only uppercase the first character of the acronym: `XmlFormatter`, not `XMLFormatter`. 55 | 56 | ## [Section 3 - Declare Statements, Namespace, and Import Statements](https://www.php-fig.org/per/coding-style/#3-declare-statements-namespace-and-import-statements) 57 | 58 | The ` __CLASS__; 125 | set => ucfirst($value); 126 | } 127 | 128 | public string $four { get => __CLASS__; } 129 | } 130 | ``` 131 | 132 | ## [Section 5.2 - Switch, Case, and Match](https://www.php-fig.org/per/coding-style/#52-switch-case-match) 133 | 134 | When breaking a series of boolean operators across multiple lines, the operator MUST be at the beginning of each line, not the end of each line. 135 | 136 | (This applies to `switch`, `match`, `while`, `do while`, and any other expression.) 137 | 138 | ## [Section 6.4 - Operator placement](https://www.php-fig.org/per/coding-style/#64-operator-placement) 139 | 140 | When breaking a series of chained operations across multiple lines, the operator MUST be at the beginning of each line, not the end of each line, and all lines but the first MUST be indented. Examples include `??` and ternary conditionals. 141 | 142 | ```php 143 | The intent of this guide is to reduce cognitive friction when scanning code from 41 | > different authors. It does so by enumerating a shared set of rules and expectations 42 | > about how to format PHP code. 43 | > When various authors collaborate across multiple projects, it helps to have one set 44 | > of guidelines to be used among all those projects. Thus, the benefit of this guide is 45 | > not in the rules themselves, but in the sharing of those rules. 46 | 47 | This PER extends, expands and replaces PSR-12, and is therefore also an extension of PSR-1. 48 | With PSR-12 being the base of this PER, a list of differences is provided below to assist with migration, 49 | but it should be considered as an independent specification. 50 | 51 | This PER will include coding style guidelines related to new functionality added to PHP 52 | after the publication of PSR-12. This PER will also include clarifications on the text of 53 | PSR-12. 54 | 55 | 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. 56 | 57 | ### 3.2. Non-Goals 58 | 59 | It is not the intention of this PER to add entirely new coding style guidelines. It will 60 | also not change anything stipulated in PSR-1 and PSR-12. 61 | 62 | ## 4. Versioning 63 | 64 | New releases of this PER are assigned version numbers in keeping with [semantic versioning](https://semver.org/). 65 | Semantic versioning is well defined when applied to software releases but has no common definition in other contexts. 66 | This PER applies the following meanings: 67 | 68 | * **Patch** versions may contain: 69 | * Any changes that do not alter the underlying requirements of this PER, such as fixing typos, adding clarifications or 70 | other modifications with no compatibility impact. 71 | * **Minor** versions may additionally: 72 | * Add new requirements for PHP syntax previously unspecified in this PER. 73 | * Add, remove or alter requirements in a way that is both more permissive and backwards compatible for implementers. 74 | * **Major** versions may additionally: 75 | * Add, remove or alter any requirements. 76 | 77 | Projects are expected to pin their own coding style guidelines to a major version of this PER, allowing for regular 78 | upgrades to minor and patch releases as they are published. When performing such upgrades, it is intended that no change 79 | to existing code is required to maintain compliance with all requirements and recommendations of this PER. This ensures 80 | new code contributions processed by an automatic formatter follow (or disregard) recommendations consistently with the 81 | existing code. 82 | 83 | Please note this backwards compatibility promise does not extend to projects that use new PHP syntax yet to be specified 84 | in this PER. In this circumstance, a minor version may introduce new requirements that are effectively breaking changes. 85 | 86 | It is ultimately determined whether a meaningful change may be included in a minor release on a case-by-case basis by 87 | consensus. The addition of `MAY` or `OPTIONAL` requirements or the removal of requirements with non-optional RFC 2119 88 | keywords will not always meet the criteria for minor release. For example, specifying that projects may use tabs instead 89 | of spaces for indentation creates a new implicit requirement that projects must use one style consistently; this new 90 | burden on projects to reformat incoming contributions to their chosen style defines the change as major. 91 | 92 | ## 5. People 93 | 94 | ### 5.1. Editor: 95 | 96 | * Larry Garfield 97 | 98 | ### 5.2. Sponsor: 99 | 100 | * Chris Tankersley 101 | 102 | ### 5.3. Working Group Members: 103 | 104 | * Alexander Makarov 105 | * Ken Guest 106 | * Korvin Szanto 107 | * Luke Diggins 108 | 109 | ### 5.4. Special Thanks 110 | 111 | * Everyone involved in PSR-1, PSR-2, PSR-12. 112 | 113 | ## 6. Votes 114 | 115 | * **Entrance Vote:** https://groups.google.com/g/php-fig/c/YqPDYGK0RhM/m/pJmThkNKBgAJ 116 | 117 | ## 7. Relevant Links 118 | 119 | _**Note:** Order descending chronologically._ 120 | 121 | * **[Migration Document: PER-CS v2.0 to v3.0](migration-3.0.md)** 122 | * **[Migration Document: PER-CS v1.0 to v2.0](migration-2.0.md)** 123 | * **PSR-12:** https://www.php-fig.org/psr/psr-12/ 124 | * **PSR-2:** https://www.php-fig.org/psr/psr-2/ 125 | * **PSR-1:** https://www.php-fig.org/psr/psr-1/ 126 | -------------------------------------------------------------------------------- /migration-2.0.md: -------------------------------------------------------------------------------- 1 | # Migrating from PER-CS v1.0 (PSR-12) to PER-CS v2.0 ### 2 | 3 | ## Summary 4 | 5 | PER-CS is the next evolution of the PSR set of Coding Standards from the 6 | PHP-FIG (Framework Interoperability Group). It extends the Coding Standards 7 | laid out in PSR-12 to the newest functionality added to PHP such as the match 8 | keyword, enums, attributes, and more. 9 | 10 | This document describes the changes and additions on a section by section 11 | basis between PER-CS v2.0 and PER-CS v1.0 (which is a direct equivalent of 12 | PSR12 with very minor changes). 13 | 14 | It is derived in part from [a GitHub-generated diff](https://github.com/php-fig/per-coding-style/compare/1.0.0...2.0.0#files_bucket) 15 | and focuses on the changes on a section-by-section basis as its focus is to be more readable. 16 | 17 | This document intends to provide a summary of these changes that can 18 | then be used to drive action lists for toolset producers to support PER-CS v2.0. 19 | 20 | This document is non-normative. The published [2.0 PER-CS](https://www.php-fig.org/per/coding-style/) specification 21 | is the canonical source for the PER-CS formatting expectations. 22 | 23 | ## [Section 2.6 - Trailing Commas](https://www.php-fig.org/per/coding-style/#26-trailing-commas) 24 | 25 | Numerous constructs now allow a sequence of values to have an optional trailing 26 | comma: 27 | * If the final item is on the same line then there MUST NOT be a trailing comma 28 | * If the final item is not on the same line then there MUST be a trailing comma 29 | 30 | ```php 31 | create() 106 | ->prepare() 107 | ->run(); 108 | ``` 109 | 110 | ## [Section 4.8 - Function Callable References](https://www.php-fig.org/per/coding-style/#48-function-callable-references) 111 | 112 | Function callable references - there must not be whitespace surrounding the '...' operator () 113 | 114 | ```php 115 | doSomething(...); 117 | ``` 118 | 119 | ## [Section 5.2 - Switch, Case, Match](https://www.php-fig.org/per/coding-style/#52-switch-case-match) 120 | 121 | The match keyword is now covered. 122 | 123 | ```php 124 | 'Foo', 127 | 'bar' => 'Bar', 128 | default => 'Baz', 129 | }; 130 | ``` 131 | 132 | ```php 133 | 'First case', 136 | 1, 2, 3 => multipleCases(), 137 | default => 'Default case', 138 | }; 139 | ``` 140 | 141 | ## [Section 7.1 - Short Closures](https://www.php-fig.org/per/coding-style/#71-short-closures) 142 | 143 | A new subsection about Short Closures, as per the link above. Example as follows: 144 | 145 | ```php 146 | $x + $y; 148 | 149 | $func = fn(int $x, int $y): int 150 | => $x + $y; 151 | 152 | $func = fn( 153 | int $x, 154 | int $y, 155 | ): int 156 | => $x + $y; 157 | 158 | $result = $collection->reduce(fn(int $x, int $y): int => $x + $y, 0); 159 | ``` 160 | 161 | ## [Section 9 - Enumerations](https://www.php-fig.org/per/coding-style/#9-enumerations) 162 | 163 | Enums are now covered, as per the link above. Please see below for examples. 164 | 165 | ```php 166 | 1, 5, 7], 240 | [ 241 | 'nested', 242 | 'array', 243 | ], 244 | ]; 245 | ``` 246 | 247 | ## [Section 12 - Attributes](https://www.php-fig.org/per/coding-style/#12-attributes) 248 | 249 | This is a new section, as per the above link. 250 | The following is an example of valid usage. 251 | 252 | ```php 253 | $b) { 64 | $foo->bar($arg1); 65 | } else { 66 | BazClass::bar($arg2, $arg3); 67 | } 68 | } 69 | 70 | final public static function bar() 71 | { 72 | // ... 73 | } 74 | } 75 | 76 | enum Beep: int 77 | { 78 | case Foo = 1; 79 | case Bar = 2; 80 | 81 | public function isOdd(): bool 82 | { 83 | return $this->value() % 2; 84 | } 85 | } 86 | ``` 87 | 88 | ## 2. General 89 | 90 | ### 2.1 Basic Coding Standard 91 | 92 | Code MUST follow all rules outlined in [PSR-1]. 93 | 94 | The term "StudlyCaps" in PSR-1 MUST be interpreted as PascalCase where the first letter of 95 | each word is capitalized including the very first letter. 96 | 97 | ### 2.2 Files 98 | 99 | All PHP files MUST use the Unix LF (linefeed) line ending only. 100 | 101 | All PHP files MUST end with a non-blank line, terminated with a single LF. 102 | 103 | The closing `?>` tag MUST be omitted from files containing only PHP. 104 | 105 | ### 2.3 Lines 106 | 107 | There MUST NOT be a hard limit on line length. 108 | 109 | The soft limit on line length MUST be 120 characters. 110 | 111 | Lines SHOULD NOT be longer than 80 characters; lines longer than that SHOULD 112 | be split into multiple subsequent lines of no more than 80 characters each. 113 | 114 | There MUST NOT be trailing whitespace at the end of lines. 115 | 116 | Blank lines MAY be added to improve readability and to indicate related 117 | blocks of code except where explicitly forbidden. 118 | 119 | There MUST NOT be more than one statement per line. 120 | 121 | ### 2.4 Indenting 122 | 123 | Code MUST use an indent of 4 spaces for each indent level, and MUST NOT use 124 | tabs for indenting. 125 | 126 | ### 2.5 Keywords and Types 127 | 128 | All PHP reserved keywords and types [[1]][keywords][[2]][types] MUST be in lower case. 129 | 130 | Any new types and keywords added to future PHP versions MUST be in lower case. 131 | 132 | Short form of type keywords MUST be used i.e. `bool` instead of `boolean`, 133 | `int` instead of `integer` etc. 134 | 135 | Compound types includes intersection, union, and mixed intersection and union type declarations. PHP requires 136 | that all compound types be structured as an ORed (unioned) series of ANDs (intersections), and that each set of 137 | intersections be encased with parentheses. 138 | 139 | The union symbol `|` and intersection symbol `&` MUST NOT have a leading or trailing space. The parentheses MUST NOT 140 | have a leading or trailing space. 141 | 142 | If it is necessary to split a compound type into multiple lines: 143 | 144 | * If the type contains only intersections or only unions, then each line MUST have a single type. 145 | * If the type contains both intersections and unions, then each line MUST have a single union segment. All intersections in a segment MUST be on the same line. 146 | * The symbol on which the compound type is split MUST be at the start of each line. 147 | 148 | The following are correct ways to format compound types: 149 | 150 | ```php 151 | function foo(int|string $a): User|Product 152 | { 153 | // ... 154 | } 155 | 156 | function somethingWithReflection( 157 | \ReflectionObject 158 | |\ReflectionClass 159 | |\ReflectionMethod 160 | |\ReflectionParameter 161 | |\ReflectionProperty $reflect 162 | ): object|null { 163 | // ... 164 | } 165 | 166 | function complex(array|(ArrayAccess&Traversable) $input): ArrayAccess&Traversable 167 | { 168 | // ... 169 | } 170 | 171 | function veryComplex( 172 | array 173 | |(ArrayAccess&Traversable) 174 | |(Traversable&Countable) $input): ArrayAccess&Traversable 175 | { 176 | // ... 177 | } 178 | ``` 179 | 180 | If one of the ORed conditions is `null`, it MUST be the last item in the list. 181 | 182 | An intersection of a single simple type with `null` SHOULD be abbreviated using the `?` alternate syntax: `?T`. 183 | 184 | ### 2.6 Trailing commas 185 | 186 | Numerous PHP constructs allow a sequence of values to be separated by a comma, 187 | and the final item may have an optional comma. Examples include array key/value pairs, 188 | function arguments, closure `use` statements, `match()` statement branches, etc. 189 | 190 | If that list is contained on a single line, then the last item MUST NOT have a trailing comma. 191 | 192 | If the list is split across multiple lines, then the last item MUST have a trailing comma. 193 | 194 | The following are examples of correct comma placement: 195 | 196 | ```php 197 | function beep(string $a, string $b, string $c) 198 | { 199 | // ... 200 | } 201 | 202 | function beep( 203 | string $a, 204 | string $b, 205 | string $c, 206 | ) { 207 | // ... 208 | } 209 | 210 | $arr = ['a' => 'A', 'b' => 'B', 'c' => 'C']; 211 | 212 | $arr = [ 213 | 'a' => 'A', 214 | 'b' => 'B', 215 | 'c' => 'C', 216 | ]; 217 | 218 | $result = match ($a) { 219 | 'foo' => 'Foo', 220 | 'bar' => 'Bar', 221 | default => 'Baz', 222 | }; 223 | ``` 224 | 225 | ### 2.7 Naming 226 | 227 | This Standard RECOMMENDS following the [php-src coding standards](https://github.com/php/php-src/blob/master/CODING_STANDARDS.md#user-functionsmethods-naming-conventions) with regard to abbreviations and acronyms. 228 | 229 | Specifically: 230 | 231 | > Abbreviations and acronyms as well as initialisms SHOULD be avoided wherever possible, unless they are much more widely used than the long form (e.g. HTTP or URL). Abbreviations, acronyms, and initialisms SHOULD be treated like regular words, thus they SHOULD be written with an uppercase first character, followed by lowercase characters. 232 | 233 | ## 3. Declare Statements, Namespace, and Import Statements 234 | 235 | The header of a PHP file may consist of a number of different blocks. If present, 236 | each of the blocks below MUST be separated by a single blank line, and MUST NOT contain 237 | a blank line. Each block MUST be in the order listed below, although blocks that are 238 | not relevant may be omitted. 239 | 240 | * Opening ` 329 | 330 | 331 | 334 | 335 | 336 | ``` 337 | 338 | Declare statements MUST NOT contain any spaces and MUST be exactly `declare(strict_types=1)` 339 | (with an optional semicolon terminator). 340 | 341 | Block declare statements are allowed and MUST be formatted as below. Note position of 342 | braces and spacing: 343 | 344 | ```php 345 | declare(ticks=1) { 346 | // ... 347 | } 348 | ``` 349 | 350 | ## 4. Classes, Properties, and Methods 351 | 352 | The term "class" refers to all classes, interfaces, traits, and enums. 353 | 354 | Any closing brace MUST NOT be followed by any comment or statement on the 355 | same line. 356 | 357 | When instantiating a new class, parentheses MUST always be present even when 358 | there are no arguments passed to the constructor. For example: 359 | 360 | ```php 361 | new Foo(); 362 | ``` 363 | 364 | If class contains no additional declarations (such as an exception that exists only to extend another exception with a new type), 365 | then the body of the class SHOULD be abbreviated as `{}` and placed on the same line as the previous symbol, 366 | separated by a space. For example: 367 | 368 | ```php 369 | class MyException extends \RuntimeException {} 370 | ``` 371 | 372 | When accessing a class member immediately after instantiating a new class, the instantiation SHOULD NOT be wrapped in 373 | parentheses. For example: 374 | 375 | ```php 376 | new Foo()->someMethod(); 377 | new Foo()::someStaticMethod(); 378 | new Foo()->someProperty; 379 | new Foo()::$someStaticProperty; 380 | new Foo()::SOME_CONSTANT; 381 | ``` 382 | 383 | And the following SHOULD be avoided: 384 | 385 | ```php 386 | (new Foo())->someMethod(); 387 | ``` 388 | 389 | ### 4.1 Extends and Implements 390 | 391 | The `extends` and `implements` keywords MUST be declared on the same line as 392 | the class name. 393 | 394 | The opening brace for the class MUST go on its own line, and MUST NOT be 395 | preceded or followed by a blank line. 396 | 397 | The closing brace for the class MUST go on its own line, immediately following 398 | the last line of the class body, and MUST NOT be preceded by a blank line. 399 | 400 | The following is a validly formatted class: 401 | 402 | ```php 403 | bar($arg1); 794 | Foo::bar($arg2, $arg3); 795 | ``` 796 | 797 | Argument lists MAY be split across multiple lines, where each subsequent line 798 | is indented once. When doing so, the first item in the list MUST be on the 799 | next line, and there MUST be only one argument per line. A single argument being 800 | split across multiple lines (as might be the case with a closure or 801 | array) does not constitute splitting the argument list itself. 802 | 803 | The following examples show correct argument usage. 804 | 805 | ```php 806 | bar( 809 | $longArgument, 810 | $longerArgument, 811 | $muchLongerArgument, 812 | ); 813 | ``` 814 | 815 | ```php 816 | get('/hello/{name}', function ($name) use ($app) { 823 | return 'Hello ' . $app->escape($name); 824 | }); 825 | ``` 826 | 827 | If using named arguments, there MUST NOT be a space between the argument name 828 | and colon, and there MUST be a single space between the colon and the argument value. For example: 829 | 830 | ```php 831 | somefunction($a, b: $b, c: 'c'); 832 | ``` 833 | 834 | Method chaining MAY be put on separate lines, where each subsequent line is indented once. When doing so, the first 835 | method MUST be on the next line. For example: 836 | 837 | ```php 838 | $someInstance 839 | ->create() 840 | ->prepare() 841 | ->run(); 842 | ``` 843 | 844 | The `exit()` and `die()` functions SHOULD always be called with parentheses even if no argument is given to clearly 845 | distinguish them from an access to a constant named `exit` or `die`. For example: 846 | 847 | ```php 848 | exit(); 849 | exit(1); 850 | exit("Success!"); 851 | die(); 852 | 853 | $result = foo() ?? exit(); 854 | ``` 855 | 856 | ### 4.8 Function Callable References 857 | 858 | A function or method may be referenced in a way that creates a closure out of it, by providing `...` in place of arguments. 859 | 860 | If so, the `...` MUST NOT include any whitespace before or after. That is, the correct format is `foo(...)`. 861 | 862 | ### 4.9 Property Hooks 863 | 864 | Object properties may also include hooks, which have a number of syntactic options. 865 | 866 | When using the long form of hooks: 867 | 868 | * The opening brace MUST be on the same line as the property. 869 | * The opening brace MUST be separated from the property name or its default value by a single space. 870 | * The closing brace MUST be on its own line, and have no comment following it. 871 | * The entire body of the hook definition MUST be indented one level. 872 | * The body of each hook MUST be indented one level. 873 | * If multiple hooks are declared, they MUST be separated by at least a single line break. They 874 | MAY be separated by an additional blank line to aid readability. 875 | 876 | For example: 877 | 878 | ```php 879 | class Example 880 | { 881 | public string $newName = 'Me' { 882 | set(string $value) { 883 | if (strlen($value) < 3) { 884 | throw new \Exception('Too short'); 885 | } 886 | $this->newName = ucfirst($value); 887 | } 888 | } 889 | 890 | public string $department { 891 | get { 892 | return $this->values[__PROPERTY__]; 893 | } 894 | set { 895 | $this->values[__PROPERTY__] = $value; 896 | } 897 | } 898 | // or 899 | public string $department { 900 | get { 901 | return $this->values[__PROPERTY__]; 902 | } 903 | 904 | set { 905 | $this->values[__PROPERTY__] = $value; 906 | } 907 | } 908 | } 909 | ``` 910 | 911 | Property hooks also support multiple short-hook variations. 912 | 913 | For a `set` hook, if the argument name and type do not need to be redefined, then they MAY be omitted. 914 | 915 | If a hook consists of a single expression, then PHP allows it to be shortened using `=>`. In that case: 916 | 917 | * There MUST be a single space on either side of the `=>` symbol. 918 | * The body MUST begin on the same line as the hook name and `=>`. 919 | * Wrapping is allowed if the expression used allows for wrapping, using the rules defined elsewhere in this document. 920 | 921 | ```php 922 | class Example 923 | { 924 | public string $myName { 925 | get => __CLASS__; 926 | } 927 | 928 | public string $newName { 929 | set => ucfirst($value); 930 | } 931 | } 932 | ``` 933 | 934 | Additionally, if the following criteria are met: 935 | 936 | * There is only one hook implementation. 937 | * That hook uses the short-hook syntax. 938 | * That hook expression does not contain any wrapping. 939 | 940 | Then the hook MAY be listed entirely inline. In that case, 941 | 942 | * The hook name MUST be separated from the opening brace and the arrow operator by a single space 943 | * The semicolon ending of the hook MUST be separated from the closing brace by a single space. 944 | 945 | For example: 946 | 947 | ```php 948 | class Example 949 | { 950 | public string $myName { get => __CLASS__; } 951 | 952 | public string $newName { set => ucfirst($value); } 953 | } 954 | ``` 955 | 956 | Property hooks MAY also be defined in constructor-promoted properties. However, they 957 | MUST be only a single hook, with a short-syntax body, defined on a single line as above. 958 | If those criteria are not met, then the promoted property MUST NOT have any hooks defined 959 | inline. 960 | 961 | ```php 962 | class Example 963 | { 964 | public function __construct( 965 | public string $name { set => ucfirst($value); } 966 | ) {} 967 | } 968 | ``` 969 | 970 | The following is ***not allowed*** due to the hook being too complex: 971 | 972 | ```php 973 | class Example 974 | { 975 | public function __construct( 976 | public string $name { 977 | set { 978 | if (strlen($value) < 3) { 979 | throw new \Exception('Too short'); 980 | } 981 | $this->newName = ucfirst($value); 982 | } 983 | } 984 | ) {} 985 | } 986 | ``` 987 | 988 | ## 4.10 Interface and abstract properties 989 | 990 | Abstract properties may be defined in interfaces or abstract classes, but are required to 991 | specify if they must support `get` operations, `set` operations, or both. In the case 992 | of abstract classes, they MAY include a body for one or another hook. 993 | 994 | If there is a body for any hook, then the entire hook block MUST follow 995 | the same rules as for defined hooks above. The only difference is that 996 | a hook that has no body specified have a single semicolon after the hook 997 | keyword, with no space before it. 998 | 999 | ```php 1000 | abstract class Example { 1001 | abstract public string $name { 1002 | get => ucfirst($this->name); 1003 | set; 1004 | } 1005 | } 1006 | ``` 1007 | 1008 | If there is no body for either hook, then the following rules apply: 1009 | 1010 | * The operation block MUST be on the same line as the property. 1011 | * There MUST be a single space between the property name and the operation block `{}`. 1012 | * There MUST be a single space after the opening `{`. 1013 | * There MUST be a single space before the closing `}`; 1014 | * There MUST NOT be a space between the operation and its required semicolon. 1015 | * If multiple operations are specified, they MUST be separated by a single space. 1016 | * The `get` operation MUST be listed before the `set` operation. 1017 | 1018 | ```php 1019 | interface Example 1020 | { 1021 | public string $readable { get; } 1022 | 1023 | public string $writeable { set; } 1024 | 1025 | public string $both { get; set; } 1026 | } 1027 | ``` 1028 | 1029 | ## 5. Control Structures 1030 | 1031 | The general style rules for control structures are as follows: 1032 | 1033 | - There MUST be one space after the control structure keyword 1034 | - There MUST NOT be a space after the opening parenthesis 1035 | - There MUST NOT be a space before the closing parenthesis 1036 | - There MUST be one space between the closing parenthesis and the opening 1037 | brace 1038 | - The structure body MUST be indented once 1039 | - The body MUST be on the next line after the opening brace 1040 | - The closing brace MUST be on the next line after the body 1041 | 1042 | The body of each structure MUST be enclosed by braces. This standardizes how 1043 | the structures look and reduces the likelihood of introducing errors as new 1044 | lines get added to the body. 1045 | 1046 | ### 5.1 `if`, `elseif`, `else` 1047 | 1048 | An `if` structure looks like the following. Note the placement of parentheses, 1049 | spaces, and braces; and that `else` and `elseif` are on the same line as the 1050 | closing brace from the earlier body. 1051 | 1052 | ```php 1053 | 'First case', 1143 | 1, 2, 3 => multipleCases(), 1144 | default => 'Default case', 1145 | }; 1146 | ``` 1147 | 1148 | ### 5.3 `while`, `do while` 1149 | 1150 | A `while` statement looks like the following. Note the placement of 1151 | parentheses, spaces, and braces. 1152 | 1153 | ```php 1154 | $value) { 1244 | // ... 1245 | } 1246 | ``` 1247 | 1248 | ### 5.6 `try`, `catch`, `finally` 1249 | 1250 | A `try-catch-finally` block looks like the following. Note the placement of 1251 | parentheses, spaces, and braces. 1252 | 1253 | ```php 1254 | $b) { 1301 | $foo = $a + $b * $c; 1302 | } else { 1303 | $foo = $a |> log(...) |> round(...); 1304 | } 1305 | ``` 1306 | 1307 | As of writing, this applies to: 1308 | 1309 | * `** * / % + -` [arithmetic][] operators 1310 | * `< <= > >= == != === !== <> <=>` [comparison][] operators 1311 | * `= += -= *= **= /= .= %= &= |= ^= <<= >>= ??=` [assignment][] operators 1312 | * `<< >> & ^ |` [bitwise][] operators 1313 | * `&& || and xor or` [logical][] operators 1314 | * `.` [string][] operator ("concatenation") 1315 | * `instanceof` [type][] operator 1316 | * `|>` [functional][] operator ("pipe") 1317 | 1318 | ### 6.3. Ternary operators 1319 | 1320 | The conditional operator, also known simply as the ternary operator, MUST be 1321 | preceded and followed by at least one space around both the `?` 1322 | and `:` characters: 1323 | 1324 | ```php 1325 | $variable = $foo ? 'foo' : 'bar'; 1326 | ``` 1327 | 1328 | When the middle operand of the conditional operator is omitted, the operator 1329 | MUST follow the same style rules as other binary [comparison][] operators: 1330 | 1331 | ```php 1332 | $variable = $foo ?: 'bar'; 1333 | ``` 1334 | 1335 | ### 6.4. Operator's placement 1336 | 1337 | A statement that includes an operator MAY be split across multiple lines, where 1338 | each subsequent line is indented once. When doing so, the operator MUST be 1339 | placed at the beginning of the new line; ternaries MUST occupy 3 lines, never 2. 1340 | 1341 | For example: 1342 | 1343 | ```php 1344 | ' 1357 | |> strtoupper(...) 1358 | |> htmlspecialchars(...); 1359 | ``` 1360 | 1361 | ## 7. Closures 1362 | 1363 | Closures, also known as anonymous functions, MUST be declared with a space 1364 | after the `function` keyword, and a space before and after the `use` keyword. 1365 | 1366 | The opening brace MUST go on the same line, and the closing brace MUST go on 1367 | the next line following the body. 1368 | 1369 | There MUST NOT be a space after the opening parenthesis of the argument list 1370 | or variable list, and there MUST NOT be a space before the closing parenthesis 1371 | of the argument list or variable list. 1372 | 1373 | In the argument list and variable list, there MUST NOT be a space before each 1374 | comma, and there MUST be one space after each comma. 1375 | 1376 | Closure arguments with default values MUST go at the end of the argument 1377 | list. 1378 | 1379 | If a return type is present, it MUST follow the same rules as with normal 1380 | functions and methods; if the `use` keyword is present, the colon MUST follow 1381 | the `use` list closing parentheses with no spaces between the two characters. 1382 | 1383 | A closure declaration looks like the following. Note the placement of 1384 | parentheses, commas, spaces, and braces: 1385 | 1386 | ```php 1387 | bar( 1469 | $arg1, 1470 | function ($arg2) use ($var1) { 1471 | // ... 1472 | }, 1473 | $arg3, 1474 | ); 1475 | ``` 1476 | 1477 | ### 7.1 Short Closures 1478 | 1479 | Short closures, also known as arrow functions, MUST follow the same guidelines 1480 | and principles as long closures above, with the following additions. 1481 | 1482 | The `fn` keyword MUST NOT be succeeded by a space. 1483 | 1484 | The `=>` symbol MUST be preceded and succeeded by a space. 1485 | 1486 | The semicolon at the end of the expression MUST NOT be preceded by a space. 1487 | 1488 | The expression portion MAY be split to a subsequent line. If so, the `=>` MUST be included 1489 | on the second line, and MUST be indented once. 1490 | 1491 | The following examples show proper common usage of short closures. 1492 | 1493 | ```php 1494 | $func = fn(int $x, int $y): int => $x + $y; 1495 | 1496 | $func = fn(int $x, int $y): int 1497 | => $x + $y; 1498 | 1499 | $func = fn( 1500 | int $x, 1501 | int $y, 1502 | ): int 1503 | => $x + $y; 1504 | 1505 | $result = $collection->reduce(fn(int $x, int $y): int => $x + $y, 0); 1506 | ``` 1507 | 1508 | ## 8. Anonymous Classes 1509 | 1510 | Anonymous Classes MUST follow the same guidelines and principles as closures 1511 | in the above section. 1512 | 1513 | ```php 1514 | 1, 5, 7], 1693 | [ 1694 | 'nested', 1695 | 'array', 1696 | ], 1697 | ]; 1698 | ``` 1699 | 1700 | ## 12. Attributes 1701 | 1702 | ### 12.1 Basics 1703 | 1704 | Attribute names MUST immediately follow the opening attribute block indicator `#[` with no space. 1705 | 1706 | If an attribute has no arguments, the `()` MUST be omitted. 1707 | 1708 | The closing attribute block indicator `]` MUST follow the last character of the attribute name or the closing `)` of 1709 | its argument list, with no preceding space. 1710 | 1711 | The construct `#[...]` is referred to as an "attribute block" in this document. 1712 | 1713 | ### 12.2 Placement 1714 | 1715 | Attributes on classes, methods, functions, constants and properties MUST 1716 | be placed on their own line, immediately prior to the structure being described. 1717 | 1718 | For attributes on parameters, if the parameter list is presented on a single line, 1719 | the attribute MUST be placed inline with the parameter it describes, separated by a single space. 1720 | If the parameter list is split into multiple lines for any reason, the attribute MUST be placed on 1721 | its own line prior to the parameter, indented the same as the parameter. If the parameter list 1722 | is split into multiple lines, a blank line MAY be included between one parameter and the attributes 1723 | of the following parameter in order to aid readability. 1724 | 1725 | If a comment docblock is present on a structure that also includes an attribute, the comment block MUST 1726 | come first, followed by any attributes, followed by the structure itself. There MUST NOT be any blank lines 1727 | between the docblock and attributes, or the attributes and the structure. 1728 | 1729 | If two separate attribute blocks are used in a multi-line context, they MUST be on separate lines with no blank 1730 | lines between them. 1731 | 1732 | ### 12.3 Compound attributes 1733 | 1734 | If multiple attributes are placed in the same attribute block, they MUST be separated by a comma with a space 1735 | following but no space preceding. If the attribute list is split into multiple lines for any reason, then the 1736 | attributes MUST be placed in separate attribute blocks. Those blocks may themselves contain multiple 1737 | attributes provided this rule is respected. 1738 | 1739 | If an attribute's argument list is split into multiple lines for any reason, then: 1740 | 1741 | * The attribute MUST be the only one in its attribute block. 1742 | * The attribute arguments MUST follow the same rules as defined for multiline function calls. 1743 | 1744 | ### 12.4 Example 1745 | 1746 | The following is an example of valid attribute usage. 1747 | 1748 | ```php 1749 | #[Foo] 1750 | #[Bar('baz')] 1751 | class Demo 1752 | { 1753 | #[Beep] 1754 | private Foo $foo; 1755 | 1756 | public function __construct( 1757 | #[Load(context: 'foo', bar: true)] 1758 | private readonly FooService $fooService, 1759 | 1760 | #[LoadProxy(context: 'bar')] 1761 | private readonly BarService $barService, 1762 | ) {} 1763 | 1764 | /** 1765 | * Sets the foo. 1766 | */ 1767 | #[Poink('narf'), Narf('poink')] 1768 | public function setFoo(#[Beep] Foo $new): void 1769 | { 1770 | // ... 1771 | } 1772 | 1773 | #[Complex( 1774 | prop: 'val', 1775 | other: 5, 1776 | )] 1777 | #[Other, Stuff] 1778 | #[Here] 1779 | public function complicated( 1780 | string $a, 1781 | 1782 | #[Decl] 1783 | string $b, 1784 | 1785 | #[Complex( 1786 | prop: 'val', 1787 | other: 5, 1788 | )] 1789 | string $c, 1790 | 1791 | int $d, 1792 | ): string { 1793 | // ... 1794 | } 1795 | } 1796 | ``` 1797 | 1798 | [PSR-1]: https://www.php-fig.org/psr/psr-1/ 1799 | [PSR-12]: https://www.php-fig.org/psr/psr-12/ 1800 | [keywords]: https://php.net/manual/en/reserved.keywords.php 1801 | [types]: https://php.net/manual/en/reserved.other-reserved-words.php 1802 | [arithmetic]: https://php.net/manual/en/language.operators.arithmetic.php 1803 | [assignment]: https://php.net/manual/en/language.operators.assignment.php 1804 | [comparison]: https://php.net/manual/en/language.operators.comparison.php 1805 | [bitwise]: https://php.net/manual/en/language.operators.bitwise.php 1806 | [logical]: https://php.net/manual/en/language.operators.logical.php 1807 | [string]: https://php.net/manual/en/language.operators.string.php 1808 | [type]: https://php.net/manual/en/language.operators.type.php 1809 | [functional]: https://php.net/manual/en/language.operators.functional.php 1810 | --------------------------------------------------------------------------------