iadvize / php-convention
Iadvize PHP 规范
Requires
- php: >=7.3
- escapestudios/symfony2-coding-standard: ~3.0
- friendsofphp/php-cs-fixer: *
- phpmd/phpmd: ^2.3.2
- squizlabs/php_codesniffer: 3.*
This package is not auto-updated.
Last update: 2024-09-14 18:26:04 UTC
README
目录
IDE 集成
故障排除
如果你有这个错误 phpcs: PHP 致命错误: 未捕获的异常 'PHP_CodeSniffer_Exception',信息 '引用的 sniff "Symfony2" 不存在'
运行以下命令: ./vendor/bin/phpcs --config-set installed_paths $PWD/vendor/escapestudios/symfony2-coding-standard,$PWD/vendor/iadvize/php-convention/phpcs
文件
-
只使用
UTF-8 无 BOM
。 -
只使用 Unix LF(换行符)行结束。
-
所有 PHP 文件必须以一个空白行结束。
-
对于非视图脚本,使用长
<?php ?>
标签。
<?php echo 'test';
- 对于视图脚本,使用短-echo
<?= ?>
标签。
<title><?=∙$title;∙?></title>
-
只包含 PHP 的文件必须省略关闭的
?>
标签。 -
行长度限制必须为
200 个字符
。 -
文件必须只包含一个命名空间声明。
-
代码必须使用
4 个空格
缩进,而不是制表符。
行数
- 可以添加空白行以提高可读性,并指明相关代码块。
// nah function foo() { $foo = 'test'; $foo = strtoupper($foo); return $foo; } // good function bar() { $foo = 'test'; $foo = strtoupper($foo); return $foo; }
- 每行不能有多个语句。
// bad $foo = substr(strtoupper('test'), 0, 1); // good $foo = 'test'; $foo = strtoupper($foo); $foo = substr($foo, 0, 1);
关键词
- 所有 PHP 关键字必须小写(例如:
true
、false
、null
等)
命名空间和使用声明
- 命名空间名称必须使用
UpperCamelCase
声明。
// bad namespace Vendor\fooBar; // bad namespace Vendor\foo_bar; // good namespace Vendor\FooBar;
-
命名空间声明从不以反斜杠开始
Vendor\Space\Space
。 -
命名空间声明前后必须有一个空白行。
-
use 声明块后必须有一个空白行。
-
use
声明不得由逗号分隔。 -
use
声明块必须按包分组。
// bad use Foo\Bar, Qux\Quux, Foo\Baz; // bad use Foo\Bar; use Qux\Quux; use Foo\Baz; // good use Foo\Bar; use Foo\Baz; use Qux\Quux; use Qux\Corge\Grault;
use
别名声明应与子命名空间名称结合。
// bad use Foo\Bar as Baz; // bad use Baz\Qux\Quux as BQQ; // good use Foo\Bar as FooBar; // good use Baz\Qux\Quux as BazQuxQuux;
注释
行内代码注释
- 注释应位于引用的代码行或代码块之前,单独一行。
// bad $foo = 'bar'; // Bar in foo // good // Foo assignment for example $foo = 'bar'; // good // Foo assignment // for example $foo = 'bar';
代码块注释
- 你必须为所有类、方法和函数添加 PHPDoc 块,但如果方法不返回任何内容,则可以省略
@return
标签。
/** * Foo * */ class Foo { /** * The description of bar * * @param string $baz The baz * * @return string The return of bar */ public function bar($baz) { // Returned value return 'Do something...'; } }
- 你必须为所有变量引用添加 PHPDoc 块。
/** @var Bar\Baz $foo Baz object */
$foo = $bar->baz();
/** * Foo * */ class Foo { /** @var string $bar It's bar! */ public $bar = ''; }
- 你不得在 PHPDoc 块中使用完全限定的类名。这意味着即使 PHPBlock 中没有其他地方引用该类,你也必须使用 use 声明声明类名。
// Bad namespace Vendor\Bar\Baz; /** * Foo * */ class Foo { /** @var \Other\MyClass $myClass */ protected $myClass; /** * @return \Other\MyClass */ public function getMyClass() { return $this->myClass; } }
// Good namespace Vendor\Bar\Baz; use Other\MyClass; /** * Foo * */ class Foo { /** @var MyClass $myClass */ protected $myClass; /** * @return MyClass */ public function getMyClass() { return $this->myClass; } }
@todo
和@fixme
必须在 PHPDoc 块中用作注释。
/** @todo Think to check value */ $foo = 'bar'; /** @fixme Change qux to quux */ $baz = 'qux';
指定你使用的对象
- 当你从抽象方法获取对象时,你应该添加
@var
标签
// bad $logger = $this->getServiceLocator()->get('logger'); // bad $this->getServiceLocator()->get('AwesomeFactory')->createAwesomeness(); // good /** @var LoggerInterface $logger */ $logger = $this->getServiceLocator()->get('logger'); // good /** @var AwesomeFactory $awesomeFactory */ $awesomeFactory = $this->getServiceLocator()->get('AwesomeFactory'); $awesomeFactory->createAwesomeness()
- 当你从显式方法获取对象时,你不应该添加
@var
标签
// bad /** * Class AwesomeFactory */ class AwesomeFactory { /** * @return Awesome */ public function createAwesomeness() { return Awesome(); } } $awesomeFactory = new AwesomeFactory(); /** @var Awesome $awesome */ $awesome = $awesomeFactory->createAwesomeness(); // good /** * Class AwesomeFactory */ class AwesomeFactory { /** * @return Awesome */ public function createAwesomeness() { return Awesome(); } } $awesomeFactory = new AwesomeFactory(); $awesome = $awesomeFactory->createAwesomeness();
命名
- 变量、方法和类名中的清晰度优于简洁性
// bad $o = new Object(); // bad class A { } // bad public function doIt() { } // good $object = new Object(); // good class Substracter { } // good public function associateChannelToOperator() { }
Boolean
变量名应该是形容词或过去分词形式。相关的获取方法应以is
或has
开头。
// bad $enablePlugin = true; // bad public function getEnablePlugin() {} // bad public function getPluginEnabled() {} // good $pluginEnabled = true; // good $visible = true; // good public function isPluginEnabled() {} // good public function isVisible() {}
DateTime
变量名应该是以At
结尾的过去分词形式。
// bad $dateUpdate = new \DateTime; // bad $endDate = new \DateTime; // good $updatedAt = new \DateTime; // good $lastLoggedAt = new \DateTime;
变量
用户变量
- 变量应该使用
lowerCamelCase
。
// bad $_foo=''; // bad $foo_bar = ''; // bad $fooBar=''; // good $fooBar∙=∙'';
- 你必须用空格分隔操作符。
// bad $foo = (5+6)/5; // good $foo∙=∙(5∙+∙6)∙/∙5;
- 你必须保持对齐。
// bad $foo = 'Ba'; $foo .= 'r'; $quux = 'Qu'; $quux .= 'x'; // good $foo = 'Ba'; $foo .= 'r'; $quux = 'Qu'; $quux .= 'x';
// bad $fooBarBazQux->bar()-> baz()->qux(); // good $fooBarBazQux ∙∙∙∙->bar() ∙∙∙∙->baz() ∙∙∙∙->qux();
全局变量
- 您必须使用
$_POST
、$_GET
和$_COOKIE
而不是$_REQUEST
。如果您使用框架,请使用Request
组件。
字符串
-
字符串必须用单引号
'hello'
包围。 -
连接字符串必须使用单引号
'foo' . $bar
-
连接字符串必须使用点周围的空格
'foo' . $bar
-
多行字符串声明必须对齐
$foo = 'Bar' .'Baz' .'Qux';
- 字符串不得与函数或方法连接
// bad $foo = ucfisrt('bar') . ' baz'; // good $foo = ucfirst('bar'); $foo = $foo . ' baz'; // very good $foo = ucfirst('bar'); $foo .= ' baz';
常量
类常量
- 常量必须使用
UPPER_SNAKE_CASE
。
// bad const MAXSIZE=5; // bad const max_size∙=∙4; // good const MAX_SIZE∙=∙5;
- 您必须用空格设置赋值运算符。
// bad const MAX_SIZE=5; // good const MAX_SIZE∙=∙5;
- 你必须保持对齐。
// bad const FOO∙∙=∙'Ba'; const FOO∙∙=∙'r'; const QUUX∙=∙'Qu'; const QUUX∙=∙'x'; // good const FOO∙∙=∙'Ba'; const FOO∙∙=∙'r'; const QUUX∙=∙'Qu'; const QUUX∙=∙'x';
类型转换
-
您必须使用
(int) $foo
而不是intval($foo)
。 -
您必须使用
(bool) $foo
而不是boolval($foo)
。 -
您必须使用
(float) $foo
而不是floatval($foo)
。 -
您必须使用
(string) $foo
而不是strval($foo)
。
// bad $foo∙=∙(string)$bar; // good $foo∙=∙(string)∙$bar;
数组
-
您必须使用
[]
语法而不是array()
。 -
包含少量数据的数组必须这样声明
$foo∙=∙['Bar',∙'Baz',∙'Qux'];
- 包含大量数据的数组必须这样声明
$foo = [ ∙∙∙∙'bar'∙∙=>∙'abc', ∙∙∙∙'baz'∙∙=>∙123, ∙∙∙∙'qux'∙∙=>∙true, ∙∙∙∙'quux'∙=>∙[ ∙∙∙∙∙∙∙∙'corge'∙∙=>∙[], ∙∙∙∙∙∙∙∙'grault'∙=>∙123.456, ∙∙∙∙], ];
- 对于大量数据的数组,行必须以逗号结尾。(易于复制/粘贴)
类、属性和方法
类
-
extends
和implements
关键字应与类名在同一行上声明。 -
类的开头大括号必须单独占一行;类的结尾大括号必须在体之后的下一行上。
<?php namespace Vendor\Foo; class Foo extends Bar implements Baz, Qux, Quux { // Do something... }
- 实现列表可以跨越多行,其中每一行后续都缩进一次。这样做时,列表中的第一项必须在下一行,并且每行只能有一个接口。
<?php namespace Vendor\Foo; class Foo extends Bar implements ∙∙∙∙Baz, ∙∙∙∙Qux, ∙∙∙∙Quux { // Do something... }
属性
- 必须声明所有属性的可见性。
// bad /** @var string Property description */ $foo = ''; // good /** @var string Property description */ public $foo = '';
- 每条语句不得声明多个属性。
// bad public $foo = '', $bar = ''; // good /** @var string Property description */ public $foo = ''; /** @var string Property description */ protected $bar = '';
- 属性名不得以单个下划线为前缀以表示
protected
或private
可见性。
// bad /** @var string Property description */ protected $_bar = ''; /** @var string Property description */ private $_baz = ''; // good /** @var string Property description */ protected $bar = ''; /** @var string Property description */ private $baz = '';
- 如果存在,则
static
声明必须放在可见性声明之后。
// bad /** @var string $foo Property description */ static public $foo = ''; // good /** @var string $foo Property description */ public static $foo = '';
方法
-
必须声明所有方法的可见性。(例如:
public|protected|private foo()
) -
方法名不应以单个下划线为前缀以表示受保护的或私有的可见性。
// bad protected function _foo() { // Do something... } // good protected function foo() { // Do something... }
- 方法名后面不应有空格。
// bad public function foo∙() { // Do something... } // good public function foo() { // Do something... }
- 在开头括号后不应有空格,并且在不带参数列表的结尾括号前不应有空格。
// bad public function foo()∙{∙ // Do something... ∙} // good public function foo() { // Do something... }
- 开头大括号必须单独占一行,并且结尾大括号必须在体之后的下一行上。
// bad public function foo()∙{ // Do something...} // good public function foo() { // Do something... }
- 在参数列表中,每个逗号前不得有空格,并且每个逗号后必须有一个空格。
// bad public function foo($bar∙,∙&$baz∙,∙$qux = []) { // Do something... } // bad public function foo(∙$bar, &$baz, $qux = []∙) { // Do something... } // good public function foo($bar,∙&$baz,∙$qux∙=∙[]) { // Do something... }
-
参数列表可以跨越多行,其中每一行后续都缩进一次。
-
这样做时,列表中的第一项必须在下一行,并且每行只能有一个参数。
-
当参数列表跨越多行时,关闭括号和打开大括号必须放在它们各自的单独一行上,它们之间有一个空格。
// good public function foo( ∙∙∙∙$bar, ∙∙∙∙&$baz, ∙∙∙∙$qux = [] ) { // Do something... }
-
如果存在,则
abstract
和final
声明必须放在可见性声明之前。 -
如果存在,则
static
声明必须放在可见性声明之后。
// bad protected abstract function foo(); static public final function bar() { // Do something... } // good abstract protected function foo(); final public static function bar() { // Do something... }
接口、特质
接口
- 接口名称必须以
Interface
结尾。
<?php namespace Vendor\Foo; /** * Interface Foo * */ interface FooInterface { /** * Set Foo * * @param string $foo */ public function setFoo($foo); }
特性
- 特性名称必须以
Trait
结尾。
<?php namespace Vendor\Foo; /** * Trait Foo * */ trait FooTrait { /** @var \Vendor\Bar */ protected $bar; /** * Set Bar * * @param string $bar */ public function setBar($bar) { $this->bar = $bar; } }
函数和方法调用
- 方法或函数名称与方法或函数开头括号之间不得有空格。
// bad foo∙(); $bar->baz∙(); // good foo(); $bar->baz();
- 在参数列表中,开头括号后不得有空格,并且结尾括号前不得有空格。
// bad foo(∙$qux∙); $bar->baz(∙$qux∙); // good foo($qux); $bar->baz($qux);
- 每个逗号前不得有空格,并且每个逗号后必须有一个空格。
// bad foo($bar∙,∙$baz∙,∙$qux); // good foo($bar,∙$baz,∙$qux);
- 参数列表可以分成多行,后续每行缩进一次。这样做时,列表中的第一个项必须在下一行,并且每行只能有一个参数。
// bad foo($longFoo, $longBar, $longBaz ); // bad foo($longFoo, $longBar, $longBaz); // good foo( ∙∙∙∙$longFoo, ∙∙∙∙$longBar, ∙∙∙∙$longBaz );
- 链式方法调用必须在第一个调用之前包裹,并缩进一次。
// bad $fooBar->baz()->qux($param); // good $fooBar ->baz() ->qux($param);
- 当您将数组作为唯一参数传递时,数组括号应与方法括号在同一行。
// bad foo( [ 'foo' => 'bar', ] ); // good foo([ 'foo' => 'bar', ]);
控制结构
一般
-
控制结构关键字后必须有一个空格
-
在开括号后不允许有空格
-
在闭括号前不允许有空格
-
在闭括号和开大括号之间必须有一个空格
-
结构体必须缩进一次
-
闭大括号必须在体之后的下一行
-
每个结构体的体必须被括号包围。这标准化了结构体的外观,并减少了在体中添加新行时引入错误的可能性。
if
,elseif
,else
- 应使用关键词
elseif
而不是else if
,以便所有控制关键词看起来像单个单词。
示例
// bad if(EXPRESSION){ // Do something... } // bad if (EXPRESSION) { // Do something... } // bad if (EXPRESSION) { // Do something... } // bad if (EXPRESSION) { // Do something... } else { // Do something... } // good if∙(EXPRESSION)∙{ ∙∙∙∙// Do something... }∙elseif∙(OTHER_EXPRESSION)∙{ ∙∙∙∙// Do something... }∙else∙{ ∙∙∙∙// Do something... }
三元运算符 (?:
)
- 不应使用嵌套的三元运算符。
示例
// bad $foo = EXPRESSION ? 'bar' : OTHER_EXPRESSION ? 'baz' : 'qux'; // good $foo∙=∙EXPRESSION∙?∙'bar'∙:∙'baz'; // good $foo∙=∙EXPRESSION ∙∙∙∙?∙'bar' ∙∙∙∙:∙'baz';
switch
和 case
-
case
语句必须从switch
缩进一次,并且break
关键字(或其他终止关键字)必须与case
体缩进相同的级别。 -
当非空
case
体有意进行穿透时,必须有一个如// no break
的注释。
示例
// bad switch(EXPRESSION) { case 0: // Do something... break; } // good switch∙(EXPRESSION)∙{ ∙∙∙∙case∙0: ∙∙∙∙∙∙∙∙// Do something... ∙∙∙∙∙∙∙∙break; ∙∙∙∙case∙1: ∙∙∙∙∙∙∙∙// Do something with no break... ∙∙∙∙∙∙∙∙// no break ∙∙∙∙case∙2: ∙∙∙∙case∙3: ∙∙∙∙case∙4: ∙∙∙∙∙∙∙∙// Do something with return instead of break... ∙∙∙∙∙∙∙∙return; ∙∙∙∙default: ∙∙∙∙∙∙∙∙// Do something in default case... ∙∙∙∙∙∙∙∙break; }
while
和 do while
示例
// bad while(EXPRESSION) { // Do something... } // bad do { // Do something... } while(EXPRESSION); // good while∙(EXPRESSION)∙{ ∙∙∙∙// Do something... } // good do∙{ ∙∙∙∙// Do something... }∙while∙(EXPRESSION);
for
示例
// bad for( $i=0;$i<10;$i++ ) { // Do something... } // good for∙($i∙=∙0;∙$i∙<∙10;∙$i++)∙{ ∙∙∙∙// Do something... }
foreach
示例
// bad foreach( $foo as $key=>$value ) { // Do something... } // good foreach∙($foo∙as∙$key∙=>∙$value)∙{ ∙∙∙∙// Do something... }
try
和 catch
示例
// bad try { // Do something... } catch(FooException $e) { // Do something... } // good try∙{ ∙∙∙∙// Do something... }∙catch∙(FooException∙$exception)∙{ ∙∙∙∙// Do something... }∙catch∙(BarException∙$exception)∙{ ∙∙∙∙// Do something... }∙finally∙{ ∙∙∙∙// Do something... }
闭包
-
闭包必须使用函数关键字后有空格,以及使用关键字前后有空格的方式声明。
-
开大括号必须在同一行,闭大括号必须紧跟在体之后的下一行。
-
参数列表或变量列表的开括号后不允许有空格,闭括号前也不允许有空格。
-
在参数列表和变量列表中,每个逗号前不允许有空格,每个逗号后必须有一个空格。
-
具有默认值的闭包参数必须放在参数列表的末尾。
-
参数列表和变量列表可以分成多行,后续每行缩进一次。
-
这样做时,列表中的第一个项必须在下一行,并且每行只能有一个参数或变量。
-
当结束列表(无论是参数还是变量)分成多行时,闭括号和开大括号必须放在它们自己的行上,两者之间有一个空格。
示例(声明)
// good $closureWithArguments∙=∙function∙($foo,∙$bar)∙{ ∙∙∙∙// Do something... }; // good $closureWithArgumentsAndVariables∙=∙function∙($foo,∙$bar)∙use∙($baz,∙$qux)∙{ ∙∙∙∙// Do something... }; // good $longArgumentsNoVariables∙=∙function∙( ∙∙∙∙$longArgumentFoo, ∙∙∙∙$longArgumentBar, ∙∙∙∙$longArgumentBaz )∙{ ∙∙∙∙// Do something... }; // good $noArgumentsLongVariables∙=∙function∙()∙use∙( ∙∙∙∙$longVariableFoo, ∙∙∙∙$longVariablBar, ∙∙∙∙$longVariableBaz )∙{ ∙∙∙∙// Do something... }; // good $longArgumentsLongVariables∙=∙function∙( ∙∙∙∙$longArgumentFoo, ∙∙∙∙$longArgumentBar, ∙∙∙∙$longArgumentBaz )∙use∙( ∙∙∙∙$longVariableFoo, ∙∙∙∙$longVariableBar, ∙∙∙∙$longVariableBaz )∙{ ∙∙∙∙// Do something... }; // good $longArgumentsShortVariables∙=∙function∙( ∙∙∙∙$longArgumentFoo, ∙∙∙∙$longArgumentBar, ∙∙∙∙$longArgumentBaz )∙use∙($variableFoo)∙{ ∙∙∙∙// Do something... }; // good $shortArgumentsLongVariables∙=∙function∙($argumentFoo)∙use∙( ∙∙∙∙$longVariableFoo, ∙∙∙∙$longVariableBar, ∙∙∙∙$longVariableBaz )∙{ ∙∙∙∙// Do something... };
示例(使用)
$foo->bar( ∙∙∙∙$argumentFoo, ∙∙∙∙function∙($argumentBar)∙use∙($variableFoo)∙{ ∙∙∙∙∙∙∙∙// Do something... ∙∙∙∙}, ∙∙∙∙$argumentBaz );
最佳实践
日期
-
必须使用
new \DateTime('2014-01-01 00:00:00')
而不是date('2014-01-01 00:00:00')
。 -
必须使用
new \DateTime('Sunday')
而不是strtotime('Sunday')
。
可读性
- 尽可能避免超过2层的嵌套,并优先使用“尽早返回”结构。
// bad $response = []; if ($foo) { foreach ($foo->getBars() as $bar) { if ($bar->hasBaz()) { // 3 nested levels } } } return $response; // good $response = []; if (!$foo) { return $response; } foreach ($foo->getBars() as $bar) { if ($bar->hasBaz()) { // only 2 nested levels } } return $response;