定制 forrest79/phpcs 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

forrest79/phpcs

最新稳定版本:v2.3

Composer 安装命令:

composer require forrest79/phpcs

包简介

Forrest79 - PHP Coding Standard - PHP Code Sniffer rules

README 文档

README

Latest Stable Version Monthly Downloads License Build

Based on (no more developed) https://github.com/consistence/coding-standard and work of https://github.com/klapuch. Thanks!

Installation

The recommended way to install Forrest79 PHP Coding Standard is through Composer:

composer require --dev forrest79/phpcs

Forrest79 PHP Coding Standard requires PHP 8.0.

How to use it:

  • Create your CS XML and include this Forrest79CodingStandard:
<?xml version="1.0"?> <ruleset name="MyOwnCS"> <rule ref="./Forrest79CodingStandard/ruleset.xml"/> </ruleset>
  • Or you can use version with fully qualified global functions (\ prefix before global functions i.e. \is_array($x)) and constants (\ prefix before global constants i.e. \FILE_APPEND):
<?xml version="1.0"?> <ruleset name="MyOwnCS"> <rule ref="./Forrest79CodingStandard/ruleset-fully-qualified-global.xml"/> </ruleset>
  • You can use it and ignore some rules.
<?xml version="1.0"?> <ruleset name="MyOwnCS"> <rule ref="./Forrest79CodingStandard/ruleset.xml"> <exclude name="Forrest79CodingStandard.Exceptions.ExceptionDeclaration.NotChainable"/> </rule> </ruleset>
  • Or just concrete files.
<rule ref="Forrest79CodingStandard.Exceptions.ExceptionDeclaration.NotChainable"> <exclude-pattern>tests/Sniffs/TestCase.php</exclude-pattern> </rule>

PSR-4 settings

  • Recommend is to proper set PSR-4 via these settings:
<rule ref="SlevomatCodingStandard.Files.TypeNameMatchesFileName"> <properties> <property name="rootNamespaces" type="array" value="  apps/home/app/src=>Home\App,  apps/home/tests/src=>Home\Tests,  packages/internals/src=>Forrest79,  tools/src=>Tools,  "/> </properties> </rule>
  • key is directory, value is namespace

Custom sniffs

Exceptions\ExceptionDeclarationSniff

Forrest79CodingStandard.Exceptions.ExceptionDeclarationSniff.NotEndingWithException

Or exceptions should have Exception suffix.

Forrest79CodingStandard.Exceptions.ExceptionDeclarationSniff.NotChainable

Exceptions should be chainable, last constructor argument must be \Throwable.

Forrest79CodingStandard.Exceptions.ExceptionDeclarationSniff.IncorrectExceptionDirectory

All exceptions should be in Exceptions subdirectory. You can change subdirectory name via settings:

<rule ref="Forrest79CodingStandard.Exceptions.ExceptionDeclaration"> <properties> <property name="exceptionsDirectoryName" type="string" value="exceptions"/> </properties> </rule>

Methods\MethodStructureSniff

Forrest79CodingStandard.Methods.MethodStructureSniff.AlphabeticalOrder

Check if class has public methods in alphabetical order. Set files via settings:

<rule ref="Forrest79CodingStandard.Methods.MethodStructure"> <properties> <property name="checkFiles" type="array" value="  apps/home/app/src/Configurator.php,  "/> </properties> </rule>

NamingConventions\MethodStructureSniff

Forrest79CodingStandard.NamingConventions.ValidVariableNameSniff.NotCamelCaps

Check camel caps variable names.

Nette\FinalInjectMethodSniff

Forrest79CodingStandard.Nette.FinalInjectMethodSniff.MissingFinal

For Nette Framework. If some presenter or other object uses inject functionality, class should be final or inject methods should be final.

Nette\ParentCallSniff

Forrest79CodingStandard.Nette.ParentCallSniff.MissingParent

For Nette Framework. In presenters, all beforeRender methods should call their parent.

Nette\PresenterMethodsSniff

Forrest79CodingStandard.Nette.PresenterMethodsSniff.NotProtected

For Nette Framework. In presenters, all startup, beforeRender and createComponent methods should be protected.

General naming conventions

  • Avoid abbreviations, use them only if long name would be less readable.
  • For 2-letter shortcuts use UPPERCASE, for longer PascalCase.
<?php use Foo\IP\Bar; use Foo\Php\Bar; use Foo\UI\Bar; use Foo\Xml\Bar;

General formatting conventions

  • Tab indentation is used.
  • Files end with a single blank line \n.
  • Unix-style (LF) line endings \n are used.
  • If there is a list of information, where ordering has no semantic meaning, the list is sorted alphabetically.
    • Sorting concatenated words (e.g. PascalCase) takes into account original words:
<?php use LogAware; use LogFactory; use LogLevel; use LogStandard; use LogableTrait; use LoggerInterface;

PHP files

  • Contains only PHP code (no inline HTML etc.).
  • File does not have the closing tag ?>.
  • There are no characters (including BOM) before the PHP opening tag.
  • Long opening tags are used (always <?php, never <?).
  • There is one empty line after the line with the open tag.
  • File either declares new symbols (classes, functions, constants, etc.) and causes no other side effects, or executes logic with side effects, but should not do both.
  • Uses strict typing by enabling declare(strict_types = 1);.
    • This declaration is placed right behind the opening tag.
    • There is no space on each side of the = operator.
<?php declare(strict_types=1); namespace Forrest79;

Strings

  • Common strings are written using apostrophes ('). Only strings containing control characters (such as \n) may use double quotes (").
  • For concatenation of mixed strings and variables sprintf() is used. If in-place strings are not needed concatenation is done with only concatenation operator (.).
    • . is surrounded by one space on each side, unless it is on the beginning of the line.
    • Strings do not contain variables ("Hello $name!").
<?php sprintf('%s/%s', $dir, $fileName); // vs $foo . $bar;
'SELECT `id`, `name` FROM `people`' . 'WHERE `role` = 1' . 'ORDER BY `name` ASC';

Arrays

  • Short array syntax is used ([, ]) instead of the array() language construct.

Namespaces

  • Namespaces are written in PascalCase.
  • Each file contains only one namespace declaration applied to the whole file.
    • Before the line with namespace there is one empty line.
  • Types from other namespaces are imported with use.
    • use declarations are separated from namespace declaration with one empty line.
    • There is only one type imported per use declaration (one import per line).
    • use declarations are sorted alphabetically.
    • use declarations never begin with backslash (\).
<?php namespace Forrest79; use Forrest79\Bar; use Forrest79\Foo; use DateTime; use Lorem\Amet; use Lorem\Ipsum\Dolor\Foo as DolorFoo; use Lorem\Sit; use ReflectionClass; use ReflectionMethod;

Types

  • Type names are written in PascalCase.
  • Type names are nouns.
  • Types are placed in namespaces (not global space).
  • Opening brace and closing brace of type are always on a separate line.
  • All parts of types are indented with one tab.
  • Only one type per file is defined, name of this file has the same name as the type.
  • Multiple types referenced in implements are separated with comma and one space and are ordered alphabetically.
  • Types referenced in code are always referenced using Foo::class syntax, never using a string.
  • If the referenced type in static access is the "current" one, self/static is used instead of type name.
  • If type can be null, always use |null not ? - string|null instead of ?string.

Interfaces

  • Interfaces are never prefixed with I.

Scalar types

  • Short type names are used in code (int, bool). This also applies to PHP functions which offer both variants.
<?php if (!is_int($foo)) { return (int) $foo; }
  • float is always used instead of double or real. This also applies to PHP functions which offer both variants.

Variables

  • Variable names are written in camelCase.
  • global keyword is never used to declare global variables.

Properties

  • All variables rules apply.
  • All properties have explicitly declared visibility with private, protected or public.
  • var is never used.
  • Only one property is declared per statement.

Constants

  • Constant names are written in UPPER_CASE.
  • Constants are defined only inside classes using const, global constants are never defined.
  • Constants have explicitly declared visibility with private, protected or public.
  • If there are more constants, that "belong together", empty lines between them may be omitted.
<?php class Foo { const FOO = 'foo'; const VISIBILITY_PRIVATE = 'private'; const VISIBILITY_PROTECTED = 'protected'; const VISIBILITY_PUBLIC = 'public'; }

Functions

  • Function names are written in camelCase.
    • Calls to built-in PHP functions are exception to this rule and are written in snake_case.
  • There is no space between the function name and the opening parenthesis.
  • Opening brace and closing brace of type are always on separate line.
    • Exception: anonymous functions.
  • Global functions are never declared, they should be defined inside a (static) class.
  • Named functions (not anonymous) are never declared inside other functions.

Argument list

  • There should be type hint defined whenever possible (including scalar type hints).
    • Nullable types (string|null) are used to allow passing null to a type hinted argument.
  • There is no space after the opening parenthesis, and there is no space before the closing parenthesis.
  • Arguments both in function declaration and in function call are separated with comma, followed by one space (, ).
<?php class X { public function __construct(Foo $foo, string $string) { // ... } }
  • Function declaration and call with arguments on multiple lines:
    • There is only one argument per line.
<?php class X { public function __construct( Foo $foo, string $string, ) { // ... } } new X( $foo, $string, );
  • Default argument values are used only when needed to either express optional argument (only at the end of the list) or to allow passing null to a type hinted argument.
    • Nullable types (string|null) are used to allow passing null to a type hinted argument and therefore default arguments are used only for optional arguments.
    • For scalar arguments default arguments are used only for optional arguments, not to allow passing nulls (see detailed example below).
<?php class X { /**  * @param \Foo $a required type argument  * @param \Foo|null $b required argument, but nullable type needed  * @param string $c required scalar argument  * @param string|null $d required argument with nullable scalar  * @param string $e optional nullable scalar argument  * @param string|null $f optional nullable scalar argument  */ public function __construct( Foo $a, Foo|null $b, string $c, string|null $d, string $e = '', string|null $f = null ) { // ... } }
  • Variadic argument is written in this format: @param \Foo ...$foo.

Return type

  • There should be type hint defined whenever possible (including scalar type hints).
    • Nullable types (string|null) are used to allow returning null.
  • There is no space after the closing parenthesis, colon immediately follows and then there is one space between the colon and the type.
<?php class X { public function getFoo(): Foo { // ... } }
  • When there is nothing to return, void return type must be specified.
<?php class X { public function process(Foo $foo): void { $foo->bar(); } }
  • When method interrupt script, never return type must be specified.
<?php class X { public function process(Foo $foo): never { exit(1); } }

Anonymous functions

  • There is a space between the function keyword and the opening parenthesis.
  • Opening brace is NOT placed on the next line.
  • There is one space before and after the use keyword.
<?php array_walk($foo, function (Item $item) use ($bar): string { // ... });

Methods

  • All methods have explicitly declared visibility with private, protected or public.
  • Order of keywords in declaration:
    1. final/abstract,
    2. private/protected/public,
    3. static
  • Constructor is always defined with __construct name, never using the old PHP behavior - with name same as class name.
  • There is one new line before and after each function (so two new lines between two functions).
<?php class X { final public static function foo(): void { // ... } abstract public static function bar(): void { // ... } }

Control structures

  • Conditional statement is surrounded by parentheses.
    • There is no space after/before parentheses inside the statement.
    • There is one space before/after parentheses around the statement.
  • Opening brace is placed on the same line as the conditional statement.
  • else if is used instead of elseif.
  • case statements in switch are indented with one tab, and their content on following lines again with another tab.
  • case statements in switch end with a colon :.
<?php if ($foo) { // ... } if ( $foo && $bar ) { // ... } switch ($foo) { case 1: case 2: // ... break; default: // ... }
  • In switch, there must be a comment such as // no break when fall-through is intentional in a non-empty case body.
  • Empty bodies of control structures are forbidden.
    • Exception is catch, but there must be a comment explaining situation.

Expressions

  • After all operators, there is one space. Before operators, there is one space too, unless it is on the beginning of a line.
  • Logical operators && and || are always used instead of and and or.
  • All keywords are lowercase, exceptions are true, false and null.
  • Strict comparisons are used by default (===), if there is need for ==, usually a comment should be given explaining situation.
    • Magic PHP type conversions should be avoided - WRONG: ($foo), CORRECT: ($foo !== null) - only expressions already containing boolean values should be written in ($foo) form.
    • The same applies for empty function, so it is forbidden.
  • Yoda conditions should not be used.
  • If expression needs to be written on multiple lines, operators belong on the beginning of the line.
<?php if ( ($lorem >= 3 && $lorem <= 5) || $ipsum !== null ) { // ... }
  • There is always only one statement per line.
  • One blank line may be used to separate other statements.
  • If there are multiple method calls in a row, and it is needed to write this on multiple lines, all the method calls are indented (including the first one).
<?php $lorem ->ipsum() ->dolor() ->sit() ->amet();
  • Parentheses in new statements should be always present, even if there are no arguments for constructor.
<?php new Foo();
  • There is one space after type cast and no space inside the parentheses.
    • (binary) and (unset) casts are forbidden.
  • For increments and decrements respective operators ++/-- are used instead of "manual" addition/subtraction.
  • All static symbols should be accessed only with ::, never using $this.
  • echo, print, ... allowing both echo('...') and echo '' syntax are always used without parentheses and with one space after the keyword.

Closures and callables

  • Closure is preferred to use instead of a callable (callable might be required while implementing a third party interface though).
  • Closures are invoked using $closure() instead of using functions.
    • call_user_func should never be needed.
    • call_user_func_array is not needed since PHP 5.6 - argument unpacking was introduced.
<?php function foo($foo, Closure $callback): void { // ... $callback($bar); // ... } foo('foo', function (Bar $bar): void { // ... });
<?php function foo($foo, Closure $callback): void { // ... $callback(...$barArray); // ... } foo('foo', function (Bar ...$bars): void { // ... });

Exceptions

  • Type name always ends with Exception.
  • Exceptions are placed in a separate directory called Exceptions.
  • Class name describes the use-case and should be very specific.
  • Inheritance is used for implementation purposes (not for creating hierarchies) - such as Forrest79\PhpException, where $code argument is skipped.
  • Constructor requires only arguments, which are needed, the rest of the message is composed in the constructor.
    • All exceptions should support exceptions chaining (allow optional \Throwable as last argument).
    • Arguments should be stored in private properties and available via public methods, so that exception handling may use this data.
<?php namespace Forrest79\Foo; use Forrest79; class LoremException extends Forrest79\PhpException { private strinf $lorem; public function __construct(string $lorem, \Throwable $previous = null) { parent::__construct(sprintf('%s ipsum dolor sit amet', $lorem), $previous); $this->lorem = $lorem; } public function getLorem(): string { return $this->lorem; } }

##Commenting

  • // inline style comments are used, never #.
  • Inline comment has a space between // and the text.
  • If there is no explicit need to write something, it should be omitted - well named classes, variables, methods and arguments should be preferred.
  • "Commented out" code is never present.

PHPDoc

Structure for types and methods:

<?php /**  * Short description - one line (optional)  *  * Long description (optional)  *  * Documentation annotations (optional)  *  * Code analysis annotations (optional)  *  * Application annotations (optional)  *  * @param string $foo only if some optional description is needed  * @param int $bar only if some optional description is needed  * @return bool only if some optional description is needed  * @throws \MyException\BarException  * @throws \MyException\FooException  */ public function myMethod(string $foo, int $bar): bool;

Structure for properties and constants:

<?php /**  * Short description - one line (optional)  *  * Long description (optional)  *  * Documentation annotations (optional)  *  * Code analysis annotations (optional)  *  * Application annotations (optional)  *  * @var string optional description  */ private $foo;

Annotation blocks

  • Different types of annotations are grouped together (separated from other blocks by an empty line).
  • See structure above.

Short+long description

  • Optional.
  • If there is no explicit need to write something, it should be omitted - well named classes, variables, methods and arguments should be preferred.
  • Descriptions which only rephrase method names (etc.) are never written.
  • Clear code is better than long explanation.
  • Short description has only one line (with no dot at the end).
  • Long description may contain example usage.
  • In long description formatting may be used (e.g. with HTML).

Documentation annotations

  • Optional.
  • PHPDoc's annotations with documentation metadata like @author, @copyright, @see, @link, ...

Code analysis annotations

Application annotations

  • Optional.
  • Annotations, that have functional significance for the application, such as Symfony, Doctrine and custom annotations.

Multi-line annotations

  • Follows general formatting rules for dealing with separating statements to multiple lines.
  • Two spaces are used for indentation.
/**  * @ManyToMany(targetEntity="Phonenumber")  * @JoinTable(  * name="users_phonenumbers",  * joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},  * inverseJoinColumns={@JoinColumn(name="phonenumber_id", referencedColumnName="id", unique=true)},  * )  * @Foo  **/

Allowed types for @param, @return, @var

List of allowed types (long variants are used):

  • int
  • bool
  • string
  • float
  • resource
  • null
  • object
  • mixed
  • array/collection (see below)
  • type (see below)

Multiple different types are separated with |.

Mixed

  • Used when nothing is known about the type.

Array/collection

  • Written as array<int, type>, array<string, type> or list<type>.
  • If the values are of more than one type, then array<int, mixed> is used (also if there is no knowledge about the types).
  • If associative array is expected (or a Map), in description, there should be description of used format, such as array<string, string> $names format: lastName(string) => firstName (string).
  • If there are more nested arrays/collections, this is expressed with more array<>, e.g. array<int, array<string, integer>> means array of arrays of integers.

Type

  • FQN with a leading backslash.
  • If the referenced type is the "current" one, self/static is used instead of type name.
<?php use DateTime; use DateTimeImmutable; /**  * @param DateTimeImmutable $date calendar date  * @param array<string> $events  * @param int|null $interval  * @return DateTime  */ public function myMethod(DateTimeImmutable $date, array $events, int $interval = null): DateTime { // ... }

@param

  • Can be omitted when type hint is the same as annotation.
  • Annotations are in the same order as defined in the argument list.
<?php use DateTime; /**  * @param string $foo optional description  * @param int $bar optional description  * @param DateTime ...$dates optional description  */ public function myMethod(string $foo, int $bar, DateTime ...$dates) { // ... }

@return

  • If there are no return statements in the method, @return is not present.
  • Can be omitted when type hint is the same as annotation.

@var

  • If the @var annotation is the only annotation and there is no long description in the PHPDoc, then one-line format is used:
<?php /** @var string optional description */ private $foo;
  • Inline @var is used to define types for variables, where the type is not clear.
    • Uses docblock comment /** ... */.
    • Type is defined first, followed by variable name.
<?php /** @var Foo $foo optional description */ $foo = $container->getService('foo');

@throws

  • For implemented methods @throws is never used.
  • @throws is only used in interfaces or abstract methods as part of the defining contract.
  • @throws annotations are sorted alphabetically (according to the exception name).

Constants

  • @var is not used for constants (type is defined by its value).
  • If there is no need for other annotations or description, then PHPDoc is omitted.

统计信息

  • 总下载量: 14.27k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 15
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: (BSD-3-Clause and MIT) 9aa9888dfdfdbe79c7156fc6cb8ccf0664285163
  • 更新时间: 2026-01-04

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固