diff --git a/README.md b/README.md index 757926e..c458ee3 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ that's where this coding standard comes in: To have internal consistency in a co ``` You can add or exclude some locations in that file. -For a reference please see: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-Ruleset +For a reference please see: https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Annotated-Ruleset ## Usage @@ -158,7 +158,7 @@ Documentation can be previewed locally by installing [MkDocs](https://www.mkdocs Rules can be added, excluded or tweaked locally, depending on your preferences. More information on how to do this can be found here: -- [Coding Standard Tutorial](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Coding-Standard-Tutorial) -- [Configuration Options](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Configuration-Options) -- [Selectively Applying Rules](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-Ruleset#selectively-applying-rules) -- [Customisable Sniff Properties](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Customisable-Sniff-Properties) +- [Coding Standard Tutorial](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Coding-Standard-Tutorial) +- [Configuration Options](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Configuration-Options) +- [Selectively Applying Rules](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Annotated-Ruleset#selectively-applying-rules) +- [Customisable Sniff Properties](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Customisable-Sniff-Properties) diff --git a/docs/book/v3/coding-style-guide.md b/docs/book/v3/coding-style-guide.md new file mode 100644 index 0000000..1569685 --- /dev/null +++ b/docs/book/v3/coding-style-guide.md @@ -0,0 +1,1353 @@ +# Laminas Coding Style Guide + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be +interpreted as described in [RFC 2119][]. + +[RFC 2119]: http://tools.ietf.org/html/rfc2119 + +## 1. Overview + +This specification extends [PSR-12][], the coding style guide and +requires adherence to [PSR-1][], the basic coding standard. + +Like [PSR-12][], the intent of this specification is to reduce cognitive friction when +scanning code from different authors contributing to Laminas. It does so by +enumerating a shared set of rules and expectations about how to format PHP code. + +### 1.1 Previous language versions + +Throughout this document, any instructions MAY be ignored if they do not exist in versions +of PHP supported by your project. + +### 1.2 Example + +This example encompasses some of the rules below as a quick overview: + +```php +factory = $factory; + $this->pipeline = $pipeline; + $this->routes = $routes; + $this->runner = $runner; + } + + /** + * Proxies to composed pipeline to handle. + * {@inheritDocs} + */ + public function handle(ServerRequestInterface $request) : ResponseInterface + { + return $this->pipeline->handle($request); + } + + /** + * Run the application. + * + * Proxies to the RequestHandlerRunner::run() method. + */ + public function run() : void + { + $this->runner->run(); + } +} +``` + +## 2. General + +### 2.1 Basic Coding Standard + +Code MUST follow all rules outlined in [PSR-1]. + +The term 'StudlyCaps' in PSR-1 MUST be interpreted as PascalCase where the first letter of +each word is capitalized including the very first letter. + +> ### Additional Laminas rules +> +> For consistency a bunch of older PHP features SHOULD NOT be used: +> +> - The [short open tag][] SHOULD NOT be used. +> - Deprecated features SHOULD be avoided ([[7.0]][70.deprecated], +> [[7.1]][71.deprecated], [[7.2]][72.deprecated], [[7.3]][73.deprecated], +> [[7.4]][74.deprecated]) +> - The [backtick operator][] MUST NOT be used. +> - The [goto][] language construct SHOULD NOT be used. +> - The [global][] keyword MUST NOT be used. +> - The constant [PHP_SAPI][] SHOULD be used instead of the `php_sapi_name()` function. +> - [aliases][] SHOULD NOT be used. +> +> There MUST NOT be a space before a semicolon. Redundant semicolons SHOULD be avoided. +> +> Non executable code MUST be removed. +> +> There MUST be a single space after language constructs. +> +> Parentheses MUST be omitted where possible. +> +> PHP function calls MUST be in lowercase. + +### 2.2 Files + +> ### Additional Laminas rules +> +> There MAY NOT be any content before the opening tag. Inline HTML in PHP code +> SHOULD be avoided. All code MUST be executable and non executable code SHOULD +> be removed. +> +> The `declare(strict_types=1)` directive MUST be declared and be the first +> statement in a file. +> + +All PHP files MUST use the Unix LF (linefeed) line ending only. + +All PHP files MUST end with a non-blank line, terminated with a single LF. + +The closing `?>` tag MUST be omitted from files containing only PHP. + +### 2.3 Lines + +There MUST NOT be a hard limit on line length. + +The soft limit on line length MUST be 120 characters. + +Lines SHOULD NOT be longer than 80 characters; lines longer than that SHOULD +be split into multiple subsequent lines of no more than 80 characters each. + +There MUST NOT be trailing whitespace at the end of lines. + +Blank lines MAY be added to improve readability and to indicate related +blocks of code except where explicitly forbidden. + +> ### Additional Laminas rules +> +> There MAY be maximum one blank line to improve readability and to indicate +> related blocks of code except where explicitly forbidden. +> +> There MAY NOT be any blank line after opening braces and before closing braces. + +There MUST NOT be more than one statement per line. + +> ### Additional Laminas rules +> +> There MUST NOT be a space before a semicolon. Redundant semicolons SHOULD be +> avoided. + +### 2.4 Indenting and Spacing + +Code MUST use an indent of 4 spaces for each indent level, and MUST NOT use +tabs for indenting. + +> ### Additional Laminas rules +> +> Encapsed strings MAY be used instead of concatenating strings. When +> concatenating strings, there MUST be a single whitespace before and after the +> concatenation operator. The concatenation operator MUST NOT be the at the end +> of a line. If multi-line concatenation is used there MUST be an indent of 4 +> spaces. + +```php +// Encapsed strings +$a = 'foo'; +$b = 'bar'; + +$c = "I like $a and $b"; + +// Concatenating +$a = 'Hello '; +$b = $a + . 'World!'; +``` + +### 2.5 Keywords and Types + +All PHP reserved keywords [[1]][keywords] and types [[2]][types] MUST be in lower case. + +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. + +### 2.6 Variables + +> ### Additional Laminas rules +> +> Variable names MUST be declared in camelCase. + +### 2.7 Arrays + +> ### Additional Laminas rules +> +> The short array syntax MUST be used to define arrays. +> +> All values in multiline arrays must be indented with 4 spaces. +> +> All array values must be followed by a comma, including the last value. +> +> There MUST NOT be whitespace around the opening bracket or before the closing +> bracket when referencing an array. +> +> All double arrow symbols MUST be aligned to one space after the longest array +> key. + +```php +$array2 = [ + 'one' => function () { + $foo = [1, 2, 3]; + $barBar = [ + 1, + 2, + 3, + ]; + }, + 'longer' => 2, + 3 => 'three', +]; +``` + +> The short list syntax `[...]` SHOULD be used instead of `list(...)`. + +```php +[$a, $b, $c] = [1, 2, 3]; +``` + +## 3. Declare Statements, Namespace, and Import Statements + +The header of a PHP file may consist of a number of different blocks. If present, +each of the blocks below MUST be separated by a single blank line, and MUST NOT contain +a blank line. Each block MUST be in the order listed below, although blocks that are +not relevant may be omitted. + +- Opening ` ### Additional Laminas rules +> +> There MUST be a single space after the namespace keyword and there MAY NOT be +> a space around a namespace separator. +> +> Import statements MUST be alphabetically sorted. +> +> Unused import statements SHOULD be removed. +> +> Fancy group import statements MUST NOT be used. +> +> Each import statement MUST be on its own line. +> +> Import statement aliases for classes, traits, functions and constants MUST +> be useful, meaning that aliases SHOULD only be used if a class with the same +> name is imported. +> +> Classes, traits, interfaces, constants and functions MUST be imported. + +The following example illustrates a complete list of all blocks: + +```php + + + + + + +``` + +Declare statements MUST contain no spaces and MUST be exactly `declare(strict_types=1)` +(with an optional semi-colon terminator). + +Block declare statements are allowed and MUST be formatted as below. Note position of +braces and spacing: + +```php +declare(ticks=1) { + // some code +} +``` + +## 4. Classes, Properties, and Methods + +The term "class" refers to all classes, interfaces, and traits. + +Any closing brace MUST NOT be followed by any comment or statement on the +same line. + +When instantiating a new class, parentheses MUST always be present even when +there are no arguments passed to the constructor. + +```php +new Foo(); +``` + +> ### Additional Laminas rules +> +> There MUST NOT be duplicate class names. +> +> The file name MUST match the case of the terminating class name. +> +> PHP 4 style constructors MUST NOT be used. +> +> Correct class name casing MUST be used. +> +> Abstract classes MUST have a `Abstract` prefix. +> +> Exception classes MUST have a `Exception` suffix. +> +> Interface classes MUST have a `Interface` suffix. +> +> Trait classes MUST have a `Trait` suffix. +> +> For self-reference a class lower-case `self::` MUST be used without spaces +> around the scope resolution operator. +> +> Class name resolution via `::class` MUST be used instead of `__CLASS__`, +> `get_class()`, `get_class($this)`, `get_called_class()`, `get_parent_class()` +> and string reference. +> +> There MAY NOT be any whitespace around the double colon operator. +> +> Unused private methods, constants and properties MUST be removed. + +### 4.1 Extends and Implements + +The `extends` and `implements` keywords MUST be declared on the same line as +the class name. + +The opening brace for the class MUST go on its own line; the closing brace +for the class MUST go on the next line after the body. + +Opening braces MUST be on their own line and MUST NOT be preceded or followed +by a blank line. + +Closing braces MUST be on their own line and MUST NOT be preceded by a blank +line. + +```php +namespace Vendor\Package; + +use FooClass; +use BarClass as Bar; +use OtherVendor\OtherPackage\BazClass; + +class ClassName extends ParentClass implements \ArrayAccess, \Countable +{ + // constants, properties, methods +} +``` + +Lists of `implements` and, in the case of interfaces, `extends` MAY be split +across multiple lines, where each subsequent line is indented once. When doing +so, the first item in the list MUST be on the next line, and there MUST be only +one interface per line. + +```php +namespace Vendor\Package; + +use FooClass; +use BarClass as Bar; +use OtherVendor\OtherPackage\BazClass; + +class ClassName extends ParentClass implements + \ArrayAccess, + \Countable, + \Serializable +{ + // constants, properties, methods +} +``` + +### 4.2 Using traits + +The `use` keyword used inside the classes to implement traits MUST be +declared on the next line after the opening brace. + +```php +namespace Vendor\Package; + +use Vendor\Package\FirstTrait; + +class ClassName +{ + use FirstTrait; +} +``` + +Each individual trait that is imported into a class MUST be included +one-per-line and each inclusion MUST have its own `use` import statement. + +> ### Additional Laminas rules +> +> Traits MUST be sorted alphabetically. + +```php +namespace Vendor\Package; + +use Vendor\Package\FirstTrait; +use Vendor\Package\SecondTrait; +use Vendor\Package\ThirdTrait; + +class ClassName +{ + use FirstTrait; + use SecondTrait; + use ThirdTrait; +} +``` + +When the class has nothing after the `use` import statement, the class +closing brace MUST be on the next line after the `use` import statement. + +```php +namespace Vendor\Package; + +use Vendor\Package\FirstTrait; + +class ClassName +{ + use FirstTrait; +} +``` + +Otherwise, it MUST have a blank line after the `use` import statement. + +```php +namespace Vendor\Package; + +use Vendor\Package\FirstTrait; + +class ClassName +{ + use FirstTrait; + + private $property; +} +``` + +When using the `insteadof` and `as` operators they must be used as follows taking +note of indentation, spacing, and new lines. + +```php +class Talker +{ + use A, B, C { + B::smallTalk insteadof A; + A::bigTalk insteadof C; + C::mediumTalk as FooBar; + } +} +``` + +### 4.3 Properties and Constants + +Visibility MUST be declared on all properties. + +Visibility MUST be declared on all constants if your project PHP minimum +version supports constant visibilities (PHP 7.1 or later). + +The `var` keyword MUST NOT be used to declare a property. + +There MUST NOT be more than one property declared per statement. + +Property names MUST NOT be prefixed with a single underscore to indicate +protected or private visibility. That is, an underscore prefix explicitly has +no meaning. + +There MUST be a space between type declaration and property name. + +> ### Additional Laminas rules +> +> Default null values MUST be omitted for class properties. + +A property declaration looks like the following: + +```php +class ClassName +{ + public $foo; // `= null` should be omitted + public static int $bar = 0; +} +``` + +### 4.4 Methods and Functions + +Visibility MUST be declared on all methods. + +Method names MUST NOT be prefixed with a single underscore to indicate +protected or private visibility. That is, an underscore prefix explicitly has +no meaning. + +Method and function names MUST NOT be declared with space after the method name. +The opening brace MUST go on its own line, and the closing brace MUST go on the +next line following the body. There MUST NOT be a space after the opening +parenthesis, and there MUST NOT be a space before the closing parenthesis. + +> ### Additional Laminas rules +> +> There MUST be a single empty line between methods in a class. +> +> The pseudo-variable `$this` MUST NOT be called inside a static method or +> function. +> +> Returned variables SHOULD be useful and SHOULD NOT be assigned to a value and +> returned on the next line. + +A method declaration looks like the following. Note the placement of +parentheses, commas, spaces, and braces: + +```php +class ClassName +{ + public function fooBarBaz($arg1, &$arg2, $arg3 = []) + { + // method body + } +} +``` + +A function declaration looks like the following. Note the placement of +parentheses, commas, spaces, and braces: + +```php +function fooBarBaz($arg1, &$arg2, $arg3 = []) +{ + // function body +} +``` + +### 4.5 Method and Function Arguments + +In the argument list, there MUST NOT be a space before each comma, and there +MUST be one space after each comma. + +Method and function arguments with default values MUST go at the end of the argument +list. + +```php +class ClassName +{ + public function foo(int $arg1, &$arg2, $arg3 = []) + { + // method body + } +} +``` + +Argument lists MAY be split across multiple lines, where each subsequent line +is indented once. When doing so, the first item in the list MUST be on the +next line, and there MUST be only one argument per line. + +When the argument list is split across multiple lines, the closing parenthesis +and opening brace MUST be placed together on their own line with one space +between them. + +```php +class ClassName +{ + public function aVeryLongMethodName( + ClassTypeHint $arg1, + &$arg2, + array $arg3 = [] + ) { + // method body + } +} +``` + +When you have a return type declaration present, there MUST be one space after +the colon followed by the type declaration. The colon and declaration MUST be +on the same line as the argument list closing parenthesis with no spaces between +the two characters. + +```php +class ReturnTypeVariations +{ + public function functionName(int $arg1, $arg2): string + { + return 'foo'; + } + + public function anotherFunction( + string $foo, + string $bar, + int $baz + ): string { + return 'foo'; + } +} +``` + +In nullable type declarations, there MUST NOT be a space between the question mark +and the type. + +> ### Additional Laminas rules +> +> The question mark MUST be used when the default argument value is null. + +```php +class ReturnTypeVariations +{ + public function functionName(?string $arg1, ?int &$arg2 = null): ?string + { + return 'foo'; + } +} +``` + +When using the reference operator `&` before an argument, there MUST NOT be +a space after it, like in the previous example. + +There MUST NOT be a space between the variadic three dot operator and the argument +name: + +```php +public function process(string $algorithm, ...$parts) +{ + // processing +} +``` + +When combining both the reference operator and the variadic three dot operator, +there MUST NOT be any space between the two of them: + +```php +public function process(string $algorithm, &...$parts) +{ + // processing +} +``` + +### 4.6 `abstract`, `final`, and `static` + +When present, the `abstract` and `final` declarations MUST precede the +visibility declaration. + +> ### Additional Laminas rules +> +> The `final` keyword on methods MUST be omitted in final declared classes. + +When present, the `static` declaration MUST come after the visibility +declaration. + +```php +abstract class ClassName +{ + protected static $foo; + + abstract protected function zim(); + + final public static function bar() + { + // method body + } +} +``` + +### 4.7 Method and Function Calls + +When making a method or function call, there MUST NOT be a space between the +method or function name and the opening parenthesis, there MUST NOT be a space +after the opening parenthesis, and there MUST NOT be a space before the +closing parenthesis. In the argument list, there MUST NOT be a space before +each comma, and there MUST be one space after each comma. + +```php +bar(); +$foo->bar($arg1); +Foo::bar($arg2, $arg3); +``` + +Argument lists MAY be split across multiple lines, where each subsequent line +is indented once. When doing so, the first item in the list MUST be on the +next line, and there MUST be only one argument per line. A single argument being +split across multiple lines (as might be the case with an anonymous function or +array) does not constitute splitting the argument list itself. + +```php +$foo->bar( + $longArgument, + $longerArgument, + $muchLongerArgument +); +``` + +```php +somefunction($foo, $bar, [ + // ... +], $baz); + +$app->get('/hello/{name}', function ($name) use ($app) { + return 'Hello ' . $app->escape($name); +}); +``` + +## 5. Control Structures + +The general style rules for control structures are as follows: + +- There MUST be one space after the control structure keyword +- There MUST NOT be a space after the opening parenthesis +- There MUST NOT be a space before the closing parenthesis +- There MUST be one space between the closing parenthesis and the opening + brace +- The structure body MUST be indented once +- The body MUST be on the next line after the opening brace +- The closing brace MUST be on the next line after the body + +The body of each structure MUST be enclosed by braces. This standardizes how +the structures look and reduces the likelihood of introducing errors as new +lines get added to the body. + +> ### Additional Laminas rules +> +> There MUST be one single space after `break` and `continue` structures with +> a numeric argument argument. +> +> Statements MUST NOT be empty, except for catch statements. + +### 5.1 `if`, `elseif`, `else` + +An `if` structure looks like the following. Note the placement of parentheses, +spaces, and braces; and that `else` and `elseif` are on the same line as the +closing brace from the earlier body. + +```php +if ($expr1) { + // if body +} elseif ($expr2) { + // elseif body +} else { + // else body; +} +``` + +The keyword `elseif` SHOULD be used instead of `else if` so that all control +keywords look like single words. + +Expressions in parentheses MAY be split across multiple lines, where each +subsequent line is indented at least once. When doing so, the first condition +MUST be on the next line. The closing parenthesis and opening brace MUST be +placed together on their own line with one space between them. Boolean +operators between conditions MUST always be at the beginning or at the end of +the line, not a mix of both. + +```php +if ( + $expr1 + && $expr2 +) { + // if body +} elseif ( + $expr3 + && $expr4 +) { + // elseif body +} +``` + +### 5.2 `switch`, `case` + +A `switch` structure looks like the following. Note the placement of +parentheses, spaces, and braces. The `case` statement MUST be indented once +from `switch`, and the `break` keyword (or other terminating keywords) MUST be +indented at the same level as the `case` body. There MUST be a comment such as +`// no break` when fall-through is intentional in a non-empty `case` body. + +> ### Additional Laminas rules +> +> The `continue` control structure MUST NOT be used in switch statements, +> `break` SHOULD be used instead. + +```php +switch ($expr) { + case 0: + echo 'First case, with a break'; + break; + case 1: + echo 'Second case, which falls through'; + // no break + case 2: + case 3: + case 4: + echo 'Third case, return instead of break'; + return; + default: + echo 'Default case'; + break; +} +``` + +Expressions in parentheses MAY be split across multiple lines, where each +subsequent line is indented at least once. When doing so, the first condition +MUST be on the next line. The closing parenthesis and opening brace MUST be +placed together on their own line with one space between them. Boolean +operators between conditions MUST always be at the beginning or at the end of +the line, not a mix of both. + +```php +switch ( + $expr1 + && $expr2 +) { + // structure body +} +``` + +### 5.3 `while`, `do while` + +A `while` statement looks like the following. Note the placement of +parentheses, spaces, and braces. + +```php +while ($expr) { + // structure body +} +``` + +Expressions in parentheses MAY be split across multiple lines, where each +subsequent line is indented at least once. When doing so, the first condition +MUST be on the next line. The closing parenthesis and opening brace MUST be +placed together on their own line with one space between them. Boolean +operators between conditions MUST always be at the beginning or at the end of +the line, not a mix of both. + +```php +while ( + $expr1 + && $expr2 +) { + // structure body +} +``` + +Similarly, a `do while` statement looks like the following. Note the placement +of parentheses, spaces, and braces. + +```php +do { + // structure body; +} while ($expr); +``` + +Expressions in parentheses MAY be split across multiple lines, where each +subsequent line is indented at least once. When doing so, the first condition +MUST be on the next line. Boolean operators between conditions MUST +always be at the beginning or at the end of the line, not a mix of both. + +```php +do { + // structure body; +} while ( + $expr1 + && $expr2 +); +``` + +### 5.4 `for` + +A `for` statement looks like the following. Note the placement of parentheses, +spaces, and braces. + +```php +for ($i = 0; $i < 10; $i++) { + // for body +} +``` + +Expressions in parentheses MAY be split across multiple lines, where each +subsequent line is indented at least once. When doing so, the first expression +MUST be on the next line. The closing parenthesis and opening brace MUST be +placed together on their own line with one space between them. + +```php +for ( + $i = 0; + $i < 10; + $i++ +) { + // for body +} +``` + +### 5.5 `foreach` + +A `foreach` statement looks like the following. Note the placement of +parentheses, spaces, and braces. + +```php +foreach ($iterable as $key => $value) { + // foreach body +} +``` + +### 5.6 `try`, `catch`, `finally` + +A `try-catch-finally` block looks like the following. Note the placement of +parentheses, spaces, and braces. + +```php +try { + // try body +} catch (FirstThrowableType $e) { + // catch body +} catch (OtherThrowableType | AnotherThrowableType $e) { + // catch body +} finally { + // finally body +} +``` + +> ### Additional Laminas rules +> +> All catch blocks MUST be reachable. + +## 6. Operators + +Style rules for operators are grouped by arity (the number of operands they +take). + +When space is permitted around an operator, multiple spaces MAY be +used for readability purposes. + +> ### Additional Laminas rules +> +> There MUST be at least one space on either side of an equals sign used +> to assign a value to a variable. In case of a block of related +> assignments, more spaces MUST be inserted before the equal sign to +> promote readability. +> +> There MUST NOT be any white space around the object operator UNLESS +> multilines are used. +> +> Loose comparison operators SHOULD NOT be used, use strict comparison +> operators instead. e.g. use `===` instead of `==`. +> +> The null coalesce operator SHOULD be used when possible. +> +> Assignment operators SHOULD be used when possible. +> +> The `&&` and `||` operators SHOULD be used instead of `and` and `or`. + +All operators not described here are left undefined. + +### 6.1. Unary operators + +The increment/decrement operators MUST NOT have any space between +the operator and operand. + +```php +$i++; +++$j; +``` + +Type casting operators MUST NOT have any space within the parentheses. + +> ### Additional Laminas rules +> +> There MUST be one whitespace after a type casting operator. + +```php +$intValue = (int) $input; +``` + +> ### Additional Laminas rules +> +> There MUST be one whitespace after unary not. + +```php +if (! true) { + return false; +} +``` + +### 6.2. Binary operators + +All binary [arithmetic][], [comparison][], [assignment][], [bitwise][], +[logical][], [string][], and [type][] operators MUST be preceded and +followed by at least one space: + +```php +if ($a === $b) { + $foo = $bar ?? $a ?? $b; +} elseif ($a > $b) { + $foo = $a + $b * $c; +} +``` + +### 6.3. Ternary operators + +The conditional operator, also known simply as the ternary operator, MUST be +preceded and followed by at least one space around both the `?` +and `:` characters: + +```php +$variable = $foo ? 'foo' : 'bar'; +``` + +When the middle operand of the conditional operator is omitted, the operator +MUST follow the same style rules as other binary [comparison][] operators: + +```php +$variable = $foo ?: 'bar'; +``` + +## 7. Closures + +Closures MUST be declared with a space after the `function` keyword, and a +space before and after the `use` keyword. + +The opening brace MUST go on the same line, and the closing brace MUST go on +the next line following the body. + +There MUST NOT be a space after the opening parenthesis of the argument list +or variable list, and there MUST NOT be a space before the closing parenthesis +of the argument list or variable list. + +In the argument list and variable list, there MUST NOT be a space before each +comma, and there MUST be one space after each comma. + +Closure arguments with default values MUST go at the end of the argument +list. + +If a return type is present, it MUST follow the same rules as with normal +functions and methods; if the `use` keyword is present, the colon MUST follow +the `use` list closing parentheses with no spaces between the two characters. + +> ### Additional Laminas rules +> +> Inherited variables passed via `use` MUST be used in closures. + +A closure declaration looks like the following. Note the placement of +parentheses, commas, spaces, and braces: + +```php +$closureWithArgs = function ($arg1, $arg2) { + // body +}; + +$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) { + // body +}; + +$closureWithArgsVarsAndReturn = function ($arg1, $arg2) use ($var1, $var2): bool { + // body +}; +``` + +Argument lists and variable lists MAY be split across multiple lines, where +each subsequent line is indented once. When doing so, the first item in the +list MUST be on the next line, and there MUST be only one argument or variable +per line. + +When the ending list (whether of arguments or variables) is split across +multiple lines, the closing parenthesis and opening brace MUST be placed +together on their own line with one space between them. + +The following are examples of closures with and without argument lists and +variable lists split across multiple lines. + +```php +$longArgs_noVars = function ( + $longArgument, + $longerArgument, + $muchLongerArgument +) { + // body +}; + +$noArgs_longVars = function () use ( + $longVar1, + $longerVar2, + $muchLongerVar3 +) { + // body +}; + +$longArgs_longVars = function ( + $longArgument, + $longerArgument, + $muchLongerArgument +) use ( + $longVar1, + $longerVar2, + $muchLongerVar3 +) { + // body +}; + +$longArgs_shortVars = function ( + $longArgument, + $longerArgument, + $muchLongerArgument +) use ($var1) { + // body +}; + +$shortArgs_longVars = function ($arg) use ( + $longVar1, + $longerVar2, + $muchLongerVar3 +) { + // body +}; +``` + +Note that the formatting rules also apply when the closure is used directly +in a function or method call as an argument. + +```php +$foo->bar( + $arg1, + function ($arg2) use ($var1) { + // body + }, + $arg3 +); +``` + +## 8. Anonymous Classes + +Anonymous Classes MUST follow the same guidelines and principles as closures +in the above section. + +```php +$instance = new class {}; +``` + +The opening brace MAY be on the same line as the `class` keyword so long as +the list of `implements` interfaces does not wrap. If the list of interfaces +wraps, the brace MUST be placed on the line immediately following the last +interface. + +```php +// Brace on the same line +$instance = new class extends \Foo implements \HandleableInterface { + // Class content +}; + +// Brace on the next line +$instance = new class extends \Foo implements + \ArrayAccess, + \Countable, + \Serializable +{ + // Class content +}; +``` + +## 9. Commenting and DocBlocks + +> ### Additional Laminas rules +> +> Code SHOULD be written so it explains itself. +> +> DocBlocks and comments SHOULD only be used if necessary. They MUST NOT start +> with `#` and MUST NOT be empty. +> +> DocBlocks and comments SHOULD NOT be used for already typehinted arguments, +> except arrays. +> + +```php +/** + * Sets a single-line title + * + * The string `param` and `return` tags should be omitted as they are already + * type hinted. + * + * A `param` tag should be here to describe the array. + * + * @param array $context + */ +public function setTitle(string $title, array $context): void +{ + // ... +} +``` + +> The asterisks in a DocBlock should align, and there should be one +> space between the asterisk and tag. +> +> PHPDoc tags `@param`, `@return` and `@throws` SHOULD not be aligned or +> contain multiple spaces between the tag, type and description. +> +> If a function throws any exceptions, it SHOULD be documented with +> `@throws` tags. +> +> DocBlocks MUST follow this specific order of annotations with empty +> newline between specific groups: +> + +```php +/** + * + * + * + * + * @internal + * @deprecated + * + * @link + * @see + * @uses + * + * @param + * @return + * @throws + */ +``` + +> The annotations `@api`, `@author`, `@category`, `@created`, `@package`, +> `@subpackage` and `@version` MUST NOT be used in comments. Git commits +> provide accurate information. +> +> The words _private_, _protected_, _static_, _constructor_, _deconstructor_, +> _Created by_, _getter_ and _setter_, MUST NOT be used in comments. +> +> The `@var` tag MAY be used in inline comments to document the _Type_ +> of properties. Single-line property comments with a `@var` tag SHOULD +> be written as one-liners. The `@var` MAY NOT be used for constants. +> +> The correct tag case of PHPDocs and PHPUnit tags MUST be used. +> +> Inline DocComments MAY be used at the end of the line, with at least a +> single space preceding. Inline DocComments MUST NOT be placed after curly +> brackets. +> +> Heredoc and nowdoc tags MUST be uppercase without spaces. + +[PSR-1]: https://www.php-fig.org/psr/psr-1/ +[PSR-12]: https://www.php-fig.org/psr/psr-12/ +[keywords]: https://www.php.net/manual/reserved.keywords.php +[types]: https://www.php.net/manual/reserved.other-reserved-words.php +[arithmetic]: https://www.php.net/manual/language.operators.arithmetic.php +[assignment]: https://www.php.net/manual/language.operators.assignment.php +[comparison]: https://www.php.net/manual/language.operators.comparison.php +[bitwise]: https://www.php.net/manual/language.operators.bitwise.php +[logical]: https://www.php.net/manual/language.operators.logical.php +[string]: https://www.php.net/manual/language.operators.string.php +[type]: https://www.php.net/manual/language.operators.type.php +[short open tag]: https://www.php.net/manual/language.basic-syntax.phptags.php +[70.deprecated]: https://www.php.net/manual/migration70.deprecated.php +[71.deprecated]: https://www.php.net/manual/migration71.deprecated.php +[72.deprecated]: https://www.php.net/manual/migration72.deprecated.php +[73.deprecated]: https://www.php.net/manual/migration73.deprecated.php +[74.deprecated]: https://www.php.net/manual/migration74.deprecated.php +[backtick operator]: https://www.php.net/manual/language.operators.execution.php +[goto]: https://www.php.net/manual/control-structures.goto.php +[global]: https://www.php.net/manual/language.variables.scope.php#language.variables.scope.global +[PHP_SAPI]: https://www.php.net/manual/function.php-sapi-name.php#refsect1-function.php-sapi-name-notes +[aliases]: https://www.php.net/manual/aliases.php diff --git a/docs/book/v3/intro.md b/docs/book/v3/intro.md new file mode 100644 index 0000000..4b402b0 --- /dev/null +++ b/docs/book/v3/intro.md @@ -0,0 +1,143 @@ +# Introduction + +**This specification extends and expands [PSR-12](https://github.com/php-fig/fig-standards/blob/master/proposed/extended-coding-style-guide.md), +the extended coding style guide and requires adherence to [PSR-1](https://www.php-fig.org/psr/psr-1), +the basic coding standard.** + +These are minimal specifications and don't address all factors, including things like: + +- whitespace around operators +- alignment of array keys and operators +- alignment of object operations +- how to format multi-line conditionals +- what and what not to import, and how +- etc. + +Contributors have different coding styles and so do the maintainers. During code reviews there are regularly +discussions about spaces and alignments, where and when was said that a function needs to be imported. And +that's where this coding standard comes in: To have internal consistency in a component and between components. + +## Installation + +1. Install the module via Composer by running: + + ```bash + $ composer require --dev laminas/laminas-coding-standard + ``` + +2. Add Composer scripts into your `composer.json`: + + ```json + "scripts": { + "cs-check": "phpcs", + "cs-fix": "phpcbf" + } + ``` + +3. Create file `phpcs.xml` on base path of your repository with this content: + + ```xml + + + + + + + + + + + + + + config + src + test + + + + + ``` + +You can add or exclude some locations in that file. For a reference please see +the ["Annotated Ruleset" of PHP_CodeSniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Annotated-Ruleset). + +## Usage + +- To run checks only: + + ```bash + $ composer cs-check + ``` + +- To automatically fix many CS issues: + + ```bash + $ composer cs-fix + ``` + +## Ignoring parts of a File + +> ### Deprecation +> +> Before PHP_CodeSniffer version 3.2.0, `// @codingStandardsIgnoreStart` and +> `// @codingStandardsIgnoreEnd` were used. These are deprecated and will be +> removed in PHP_CodeSniffer version 4.0. + +Disable parts of a file: + +```php +$xmlPackage = new XMLPackage; +// phpcs:disable +$xmlPackage['error_code'] = get_default_error_code_value(); +$xmlPackage->send(); +// phpcs:enable +``` + +Disable a specific rule: + +```php +// phpcs:disable Generic.Commenting.Todo.Found +$xmlPackage = new XMLPackage; +$xmlPackage['error_code'] = get_default_error_code_value(); +// TODO: Add an error message here. +$xmlPackage->send(); +// phpcs:enable +``` + +## Development + +> ### New Rules or Sniffs +> +> New rules or Sniffs may not be introduced in minor or bugfix releases and +> should always be based on the develop branch and queued for the next major +> release, unless considered a bugfix for existing rules. + +If you want to test changes against Laminas components or your own projects, install your forked +laminas-coding-standard globally with Composer: + +```bash +$ composer global config repositories.laminas-coding-standard vcs git@github.com:/laminas-coding-standard.git +$ composer global require --dev laminas/laminas-coding-standard:dev- + +# For this to work, add this to your path: ~/.composer/vendor/bin +# Using `-s` prints the rules that triggered the errors so they can be reviewed easily. `-p` is for progress display. +$ phpcs -sp --standard=LaminasCodingStandard src test +``` + +**Make sure you remove the global installation after testing from your global +`composer.json` file!** + +Documentation can be previewed locally by installing [MkDocs](https://www.mkdocs.org/#installation) and run +`mkdocs serve`. This will start a server where you can read the docs. + +## Reference + +Rules can be added, excluded or tweaked locally, depending on your preferences. More information on how to do this can +be found here: + +- [Coding Standard Tutorial](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Coding-Standard-Tutorial) +- [Configuration Options](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Configuration-Options) +- [Selectively Applying Rules](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Annotated-Ruleset#selectively-applying-rules) +- [Customisable Sniff Properties](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Customisable-Sniff-Properties) diff --git a/mkdocs.yml b/mkdocs.yml index e9be623..dd90291 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,14 +2,18 @@ docs_dir: docs/book site_dir: docs/html extra: project: Components - current_version: v2 + current_version: v3 versions: + - v3 - v2 - v1 installation: composer_dev: true nav: - Home: index.md + - v3: + - 'Introduction': v3/intro.md + - 'Coding Style Guide': v3/coding-style-guide.md - v2: - 'Introduction': v2/intro.md - 'Coding Style Guide': v2/coding-style-guide.md