remy-theroux/php-convention

现代PHP应用的PHP约定集合

安装: 41

依赖: 0

建议者: 0

安全性: 0

星标: 0

关注者: 2

分支: 0

开放问题: 1

类型:phpcodesniffer-standard

0.2 2019-10-25 07:49 UTC

This package is auto-updated.

Last update: 2024-08-28 16:43:29 UTC


README

用法

vendor/bin/phpcs --standard=ModernPhp your_path

故障排除

标准必须通过composer插件在package dealerdirect/phpcodesniffer-composer-installer中自动安装

如果您遇到此错误 'PHP_CodeSniffer_Exception' with message 'Referenced sniff "ModernPhp" does not exist'

手动将标准添加到您的安装路径: ./vendor/bin/phpcs --config-set installed_paths $PWD/vendor/remy-theroux/php-convention

目录

  1. IDE集成
  2. 文件
  3. 关键字
  4. 注释
  5. 命名
  6. 变量
  7. 常量
  8. 类型转换
  9. 命名空间和使用声明
  10. 字符串
  11. 数组
  12. 类、属性和方法
  13. 接口、特质
  14. 函数和方法调用
  15. 控制结构
  16. 闭包
  17. 最佳实践

文件

  • 仅使用UTF-8 without 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关键字都必须小写(例如:truefalsenull等)

命名空间和使用声明

  • 命名空间名称必须声明为UpperCamelCase
// bad
namespace Vendor\fooBar;

// bad
namespace Vendor\foo_bar;

// good
namespace Vendor\FooBar;
  • 命名空间声明永远不以反斜杠开始 Vendor\Space\Space

  • namepsace声明前后必须有一个空行。

  • 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块中使用完全限定的类名。这意味着即使在PHP块的其他地方没有引用,您也必须使用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变量名应该是形容词或过去分词形式。相关getter方法应以ishas开头。
// 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,
∙∙∙∙],
];
  • 对于大量数据的数组,行必须以逗号结束。(易于复制粘贴)

类、属性和方法

  • extendsimplements 关键字应与类名在同一行声明。

  • 类的开头大括号必须单独一行;类的结尾大括号必须在主体后下一行。

<?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 = '';
  • 属性名不得以单下划线开头以表示protectedprivate可见性。
// 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...
}
  • 如果有,则abstractfinal声明必须放在可见性声明之前。

  • 如果有,则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';

switchcase

  • case 语句必须从 switch 缩进一次,并且 break 关键字(或其他终止关键字)必须与 case 体处于同一缩进级别。

  • 当非空 case 体中的贯穿是故意的时,必须有一个如 // no break 的注释。

示例

// bad
switch(EXPRESSION)
{
    case 0:
        // Do something...
    break;
}

// good
switch∙(EXPRESSION)∙{
∙∙∙∙case0:
∙∙∙∙∙∙∙∙// Do something...
∙∙∙∙∙∙∙∙break;
∙∙∙∙case1:
∙∙∙∙∙∙∙∙// Do something with no break...
∙∙∙∙∙∙∙∙// no break
∙∙∙∙case2:
∙∙∙∙case3:
∙∙∙∙case4:
∙∙∙∙∙∙∙∙// Do something with return instead of break...
∙∙∙∙∙∙∙∙return;
∙∙∙∙default:
∙∙∙∙∙∙∙∙// Do something in default case...
∙∙∙∙∙∙∙∙break;
}

whiledo 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∙($fooas$key∙=>∙$value)∙{
∙∙∙∙// Do something...
}

trycatch

示例

// 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;