PHPCSExtra ===================================================== * [Introduction](#introduction) * [Minimum Requirements](#minimum-requirements) * [Installation](#installation) + [Composer Project-based Installation](#composer-project-based-installation) + [Composer Global Installation](#composer-global-installation) + [Updating to a newer version](#updating-to-a-newer-version) * [Features](#features) * [Sniffs](#sniffs) + [Modernize](#modernize) + [NormalizedArrays](#normalizedarrays) + [Universal](#universal) * [Contributing](#contributing) * [License](#license) Introduction ------------------------------------------- PHPCSExtra is a collection of sniffs and standards for use with [PHP_CodeSniffer][phpcs-gh]. Minimum Requirements ------------------------------------------- * PHP 5.4 or higher. * [PHP_CodeSniffer][phpcs-gh] version **3.7.1** or higher. * [PHPCSUtils][phpcsutils-gh] version **1.0.8** or higher. Installation ------------------------------------------- Installing via Composer is highly recommended. [Composer](http://getcomposer.org/) will automatically install the project dependencies and register the rulesets from PHPCSExtra and other external standards with PHP_CodeSniffer using the [Composer PHPCS plugin][composer-installer-gh]. ### Composer Project-based Installation Run the following from the root of your project: ```bash composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true composer require --dev phpcsstandards/phpcsextra:"^1.1.0" ``` ### Composer Global Installation Alternatively, you may want to install this standard globally: ```bash composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true composer global require --dev phpcsstandards/phpcsextra:"^1.1.0" ``` ### Updating to a newer version If you installed PHPCSExtra using either of the above commands, you can update to a newer version as follows: ```bash # Project local install composer update phpcsstandards/phpcsextra --with-dependencies # Global install composer global update phpcsstandards/phpcsextra --with-dependencies ``` > If your project includes `require[-dev]`s for the `squizlabs/php_codesniffer`, `phpcsstandards/phpcsutils` or > `dealerdirect/phpcodesniffer-composer-installer` packages in its `composer.json` file, you may need to use > `--with-all-dependencies` instead of `--with-dependencies`. > > :bulb: **Pro-tip**: Unless your project is a PHPCS standard which actually uses any of these packages directly, > it is recommended to remove these packages from your own `composer.json` file, in favour of letting PHPCSExtra > (and potential other external PHPCS standards you use), manage the version requirements for these packages. Features ------------------------------------------- Once this project is installed, you will see three new rulesets in the list of installed standards when you run `vendor/bin/phpcs -i`: `Modernize`, `NormalizedArrays` and `Universal`. * The `Modernize` ruleset is a standard which checks code for modernization opportunaties. * The `NormalizedArrays` ruleset is a standard to check the formatting of array declarations. * The `Universal` ruleset is **NOT** a standard, but a sniff collection. It should **NOT** be included in custom rulesets as a standard as it contains contradictory rules. Instead include individual sniffs from this standard in a custom project/company ruleset to use them. Sniffs ------------------------------------------- **Legend**: * :wrench: = Includes auto-fixer. _Use the `phpcbf` command to run the fixers._ * :bar_chart: = Includes metrics. _Use `phpcs` with `--report=info` to see the metrics._ * :books: = Includes CLI documentation. _Use `phpcs` with `--generator=Text` to see the documentation._ ### Modernize #### `Modernize.FunctionCalls.Dirname` :wrench: :books: This sniff will detect and auto-fix two typical code modernizations which can be made related to the `dirname()` function: 1. Since PHP 5.3, calls to `dirname(__FILE__)` can be replaced by `__DIR__`. Errorcode: `Modernize.FunctionCalls.Dirname.FileConstant`. 2. Since PHP 7.0, nested function calls to `dirname()` can be changed to use the `$levels` parameter. Errorcode: `Modernize.FunctionCalls.Dirname.Nested`. If a [`php_version` configuration option][php_version-config] has been passed to PHPCS using either `--config-set` or `--runtime-set`, it will be respected by the sniff. In effect, this means that the sniff will only report on modernizations which can be applied for the PHP version as configured. ### NormalizedArrays #### `NormalizedArrays.Arrays.ArrayBraceSpacing` :wrench: :bar_chart: :books: Enforce consistent spacing for the open/close braces of array declarations. The sniff allows for having different settings for: - Space between the array keyword and the open parenthesis for long arrays via the `keywordSpacing` property. Accepted values: (int) number of spaces or `false` to turn this check off. Defaults to `0` spaces. - Spaces on the inside of the braces for empty arrays via the `spacesWhenEmpty` property. Accepted values: (string) `newline`, (int) number of spaces or `false` to turn this check off. Defaults to `0` spaces. - Spaces on the inside of the braces for single-line arrays via the `spacesSingleLine` property; Accepted values: (int) number of spaces or `false` to turn this check off. Defaults to `0` spaces. - Spaces on the inside of the braces for multi-line arrays via the `spacesMultiLine` property. Accepted values: (string) `newline`, (int) number of spaces or `false` to turn this check off. Defaults to `newline`. Note: if any of the above properties are set to `newline`, it is recommended to also include an array indentation sniff. This sniff will not handle the indentation. #### `NormalizedArrays.Arrays.CommaAfterLast` :wrench: :bar_chart: :books: Enforce/forbid a comma after the last item in an array declaration. By default, this sniff will: * Forbid a comma after the last array item for single-line arrays. * Enforce a comma after the last array item for multi-line arrays. This can be changed for each type or array individually by setting the `singleLine` and/or `multiLine` properties in a custom ruleset. Use any of the following values to change the properties: `enforce`, `forbid` or `skip` to not check the comma after the last array item for a particular type of array. The default for the `singleLine` property is `forbid`. The default for the `multiLine` property is `enforce`. ### Universal #### `Universal.Arrays.DisallowShortArraySyntax` :wrench: :bar_chart: :books: Disallow short array syntax. In contrast to the PHPCS native `Generic.Arrays.DisallowShortArraySyntax` sniff, this sniff will ignore short list syntax and not cause parse errors when the fixer is used. #### `Universal.Arrays.DuplicateArrayKey` :books: Detects duplicate array keys in array declarations. The sniff will make a distinction between keys which will be duplicate in all PHP version and (numeric) keys which will only be a duplicate key in [PHP < 8.0 or PHP >= 8.0][php-rfc-negative_array_index]. If a [`php_version` configuration option][php_version-config] has been passed to PHPCS using either `--config-set` or `--runtime-set`, it will be respected by the sniff and only report duplicate keys for the configured PHP version. [php-rfc-negative_array_index]: https://wiki.php.net/rfc/negative_array_index #### `Universal.Arrays.MixedArrayKeyTypes` :books: Best practice sniff: don't use a mix of integer and string keys for array items. #### `Universal.Arrays.MixedKeyedUnkeyedArray` :books: Best practice sniff: don't use a mix of keyed and unkeyed array items. #### `Universal.Classes.DisallowAnonClassParentheses` :wrench: :bar_chart: :books: Disallow the use of parentheses when declaring an anonymous class without passing parameters. #### `Universal.Classes.RequireAnonClassParentheses` :wrench: :bar_chart: :books: Require the use of parentheses when declaring an anonymous class, whether parameters are passed or not. #### `Universal.Classes.DisallowFinalClass` :wrench: :bar_chart: :books: Disallow classes being declared `final`. #### `Universal.Classes.RequireFinalClass` :wrench: :bar_chart: :books: Require all non-`abstract` classes to be declared `final`. :warning: **Warning**: the auto-fixer for this sniff _may_ have unintended side-effects for applications and should be used with care! This is considered a **_risky_ fixer**. #### `Universal.Classes.ModifierKeywordOrder` :wrench: :bar_chart: :books: Require a consistent modifier keyword order for class declarations. * This sniff contains an `order` property to specify the preferred order. Accepted values: (string) `'extendability readonly'`|`'readonly extendability'`. Defaults to `'extendability readonly'`. #### `Universal.CodeAnalysis.ConstructorDestructorReturn` :wrench: :books: * Disallows return type declarations on constructor/destructor methods - error code: `ReturnTypeFound`, auto-fixable. * Discourages constructor/destructor methods returning a value - error code: `ReturnValueFound`. If a [`php_version` configuration option][php_version-config] has been passed to PHPCS using either `--config-set` or `--runtime-set`, it will be respected by the sniff. In effect, this means that the sniff will only report on PHP4-style constructors if the configured PHP version is less than 8.0. #### `Universal.CodeAnalysis.ForeachUniqueAssignment` :wrench: :books: Detects `foreach` control structures which use the same variable for both the key as well as the value assignment as this will lead to unexpected - and most likely unintended - behaviour. Note: The fixer will maintain the existing behaviour of the code. This may not be the _intended_ behaviour. #### `Universal.CodeAnalysis.NoEchoSprintf` :wrench: :books: Detects use of the inefficient `echo [v]sprintf(...);` combi. Use `[v]printf()` instead. #### `Universal.CodeAnalysis.StaticInFinalClass` :wrench: :books: Detects using `static` instead of `self` in OO constructs which are `final`. * The sniff has modular error codes to allow for making exceptions based on the type of use for `static`. The available error codes are: `ReturnType`, `InstanceOf`, `NewInstance`, `ScopeResolution`. #### `Universal.Constants.LowercaseClassResolutionKeyword` :wrench: :bar_chart: :books: Enforce that the `class` keyword when used for class name resolution, i.e. `::class`, is in lowercase. #### `Universal.Constants.ModifierKeywordOrder` :wrench: :bar_chart: :books: Require a consistent modifier keyword order for OO constant declarations. * This sniff contains an `order` property to specify the preferred order. Accepted values: (string) `'final visibility'`|`'visibility final'`. Defaults to `'final visibility'`. #### `Universal.Constants.UppercaseMagicConstants` :wrench: :bar_chart: :books: Enforce uppercase when using PHP native magic constants, like `__FILE__` et al. #### `Universal.ControlStructures.DisallowAlternativeSyntax` :wrench: :bar_chart: :books: Disallow using the alternative syntax for control structures. * This sniff contains an `allowWithInlineHTML` property to allow alternative syntax when inline HTML is used within the control structure. In all other cases, the use of the alternative syntax will still be disallowed. Accepted values: (bool) `true`|`false`. Defaults to `false`. * The sniff has modular error codes to allow for making exceptions based on specific control structures and/or specific control structures in combination with inline HTML. The error codes follow the following pattern: `Found[ControlStructure][WithInlineHTML]`. Examples: `FoundIf`, `FoundSwitchWithInlineHTML`. #### `Universal.ControlStructures.DisallowLonelyIf` :wrench: :books: Disallow `if` statements as the only statement in an `else` block. Note: This sniff will not fix the indentation of the "inner" code. It is strongly recommended to run this sniff together with the `Generic.WhiteSpace.ScopeIndent` sniff to get the correct indentation. #### `Universal.ControlStructures.IfElseDeclaration` :wrench: :bar_chart: :books: Verify that else(if) statements with braces are on a new line. #### `Universal.Files.SeparateFunctionsFromOO` :bar_chart: :books: Enforce for a file to either declare (global/namespaced) functions or declare OO structures, but not both. * Nested function declarations, i.e. functions declared within a function/method will be disregarded for the purposes of this sniff. The same goes for anonymous classes, closures and arrow functions. * Note: This sniff has no opinion on side effects. If you want to sniff for those, use the PHPCS native `PSR1.Files.SideEffects` sniff. * Also note: This sniff has no opinion on multiple OO structures being declared in one file. If you want to sniff for that, use the PHPCS native `Generic.Files.OneObjectStructurePerFile` sniff. #### `Universal.FunctionDeclarations.NoLongClosures` :bar_chart: :books: Detects "long" closures and recommends using a named function instead. The sniff is configurable by setting any of the following properties in a custom ruleset: * `recommendedLines` (int): determines when a warning will be thrown. Defaults to `5`, meaning a warning with the errorcode `ExceedsRecommended` will be thrown if the closure is more than 5 lines long. * `maxLines` (int): determines when an error will be thrown. Defaults to `8`, meaning that an error with the errorcode `ExceedsMaximum` will be thrown if the closure is more than 8 lines long. * `ignoreCommentLines` (bool): whether or not comment-only lines should be ignored for the lines count. Defaults to `true`. * `ignoreEmptyLines` (bool): whether or not blank lines should be ignored for the lines count. Defaults to `true`. #### `Universal.FunctionDeclarations.RequireFinalMethodsInTraits` :wrench: :bar_chart: :books: Enforce non-private, non-abstract methods in traits to be declared as `final`. The available error codes are: `NonFinalMethodFound` and `NonFinalMagicMethodFound`. #### `Universal.Lists.DisallowLongListSyntax` :wrench: :books: Disallow the use of long `list`s. > For metrics about the use of long lists vs short lists, please use the `Universal.Lists.DisallowShortListSyntax` sniff. #### `Universal.Lists.DisallowShortListSyntax` :wrench: :bar_chart: :books: Disallow the use of short lists. #### `Universal.Namespaces.DisallowDeclarationWithoutName` :bar_chart: :books: Disallow namespace declarations without a namespace name. This sniff only applies to namespace declarations using the curly brace syntax. #### `Universal.Namespaces.DisallowCurlyBraceSyntax` :bar_chart: :books: Disallow the use of the alternative namespace declaration syntax using curly braces. #### `Universal.Namespaces.EnforceCurlyBraceSyntax` :bar_chart: :books: Enforce the use of the alternative namespace syntax using curly braces. #### `Universal.Namespaces.OneDeclarationPerFile` :books: Disallow the use of multiple namespaces within a file. #### `Universal.NamingConventions.NoReservedKeywordParameterNames` :books: Disallow function parameters using reserved keywords as names, as this can quickly become confusing when people use them in function calls using named parameters * The sniff has modular error codes to allow for making exceptions for specific keywords. The error codes follow the following pattern: `[keyword]Found`. #### `Universal.OOStructures.AlphabeticExtendsImplements` :wrench: :bar_chart: :books: Enforce that the names used in a class/enum "implements" statement or an interface "extends" statement are listed in alphabetic order. * This sniff contains a `orderby` property to determine the sort order to use for the statement. If all names used are unqualified, the sort order won't make a difference. However, if one or more of the names are partially or fully qualified, the chosen sort order will determine how the sorting between unqualified, partially and fully qualified names is handled. The sniff supports two sort order options: - _'name'_ : sort by the interface name only (default); - _'full'_ : sort by the full name as used in the statement (without leading backslash). In both cases, the sorting will be done using natural sort, case-insensitive. * The sniff has modular error codes to allow for selective inclusion/exclusion: - `ImplementsWrongOrder` - for "class implements" statements. - `ImplementsWrongOrderWithComments` - for "class implements" statements interlaced with comments. These will not be auto-fixed. - `ExtendsWrongOrder` - for "interface extends" statements. - `ExtendsWrongOrderWithComments` - for "interface extends" statements interlaced with comments. These will not be auto-fixed. * When fixing, the existing spacing between the names in an `implements`/`extends` statement will not be maintained. The fixer will separate each name with a comma and one space. If alternative formatting is desired, a sniff which will check and fix the formatting should be added to the ruleset. #### `Universal.Operators.DisallowLogicalAndOr` :bar_chart: :books: Enforce the use of the boolean `&&` and `||` operators instead of the logical `and`/`or` operators. :information_source: Note: as the [operator precedence](https://www.php.net/language.operators.precedence) of the logical operators is significantly lower than the operator precedence of boolean operators, this sniff does not contain an auto-fixer. #### `Universal.Operators.DisallowShortTernary` :bar_chart: :books: Disallow the use of short ternaries `?:`. While short ternaries are useful when used correctly, the principle of them is often misunderstood and they are more often than not used incorrectly, leading to hard to debug issues and/or PHP warnings/notices. #### `Universal.Operators.DisallowStandalonePostIncrementDecrement` :wrench: :bar_chart: :books: * Disallow the use of post-in/decrements in stand-alone statements - error codes: `PostDecrementFound` and `PostIncrementFound`. Using pre-in/decrement is more in line with the principle of least astonishment and prevents bugs when code gets moved around at a later point in time. * Discourages the use of multiple increment/decrement operators in a stand-alone statement - error code: `MultipleOperatorsFound`. #### `Universal.Operators.StrictComparisons` :wrench: :bar_chart: :books: Enforce the use of strict comparisons. :warning: **Warning**: the auto-fixer for this sniff _may_ cause bugs in applications and should be used with care! This is considered a **_risky_ fixer**. #### `Universal.Operators.TypeSeparatorSpacing` :wrench: :bar_chart: :books: Enforce no spaces around the union type and intersection type operators. The available error codes are: `UnionTypeSpacesBefore`, `UnionTypeSpacesAfter`, `IntersectionTypeSpacesBefore`, `IntersectionTypeSpacesAfter`. #### `Universal.PHP.OneStatementInShortEchoTag` :wrench: :books: Disallow short open echo tags ` _This sniff is especially useful for tab-indentation based standards which use the `Generic.Whitespace.DisallowSpaceIndent` sniff to enforce this._ > > **DO** make sure to set the PHPCS native `tab-width` configuration for the best results. > ```xml > > ``` > > The PHPCS native `Generic.Whitespace.DisallowTabIndent` sniff (used for space-based standards) oversteps its reach and silently does mid-line tab to space replacements as well. > However, the sister-sniff `Generic.Whitespace.DisallowSpaceIndent` leaves mid-line tabs/spaces alone. > This sniff fills that gap. #### `Universal.WhiteSpace.PrecisionAlignment` :wrench: :books: Enforce code indentation to always be a multiple of a tabstop, i.e. disallow precision alignment. Note: * This sniff does not concern itself with tabs versus spaces. It is recommended to use the sniff in combination with the PHPCS native `Generic.WhiteSpace.DisallowTabIndent` or the `Generic.WhiteSpace.DisallowSpaceIndent` sniff. * When using this sniff with tab-based standards, please ensure that the `tab-width` is set and either don't set the `$indent` property or set it to the tab-width (or a multiple thereof). * The fixer works based on "best guess" and may not always result in the desired indentation. Combine this sniff with the `Generic.WhiteSpace.ScopeIndent` sniff for more precise indentation fixes. The behaviour of the sniff is customizable via the following properties: * `indent`: the indent used for the codebase. Accepted values: (int|null) number of spaces. Defaults to `null`. If this property is not set, the sniff will look to the `--tab-width` CLI value. If that also isn't set, the default tab-width of `4` will be used. * `ignoreAlignmentBefore`: allows for providing a list of token names for which (preceding) precision alignment should be ignored. Accepted values: (array) token constant names. Defaults to an empty array. Usage example: ```xml ``` * `ignoreBlankLines`: whether or not potential trailing whitespace on otherwise blank lines should be examined or ignored. It is recommended to only set this to `false` if the standard including this sniff does not include the `Squiz.WhiteSpace.SuperfluousWhitespace` sniff (which is included in most standards). Accepted values: (bool)`true`|`false`. Defaults to `true`. Contributing ------- Contributions to this project are welcome. Clone the repo, branch off from `develop`, make your changes, commit them and send in a pull request. If unsure whether the changes you are proposing would be welcome, open an issue first to discuss your proposal. License ------- This code is released under the [GNU Lesser General Public License (LGPLv3)](LICENSE). [phpcsextra-packagist]: https://packagist.org/packages/phpcsstandards/phpcsextra [gha-qa-results]: https://github.com/PHPCSStandards/PHPCSExtra/actions/workflows/basics.yml [gha-test-results]: https://github.com/PHPCSStandards/PHPCSExtra/actions/workflows/test.yml [phpcs-gh]: https://github.com/squizlabs/PHP_CodeSniffer [phpcsutils-gh]: https://github.com/PHPCSStandards/PHPCSUtils [composer-installer-gh]: https://github.com/PHPCSStandards/composer-installer [php_version-config]: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Configuration-Options#setting-the-php-version