代码样式规范

本指南的意图是为了减少不同开发者在浏览代码时减少认知的差异。 为此列举一组如何格式化PHP代码的共用规则。

各个成员项目的共性组成了本文的样式规则。当不同的开发者在不同的项目中合作时,将会在这些不同的项目中使用一个共同的标准。 因此,本指南的好处不在于规则本身,而在于共用这些规则。

在 RFC 2119中的特性关键词"必须"(MUST),“不可”(MUST NOT),“必要”(REQUIRED),“将会”(SHALL),“不会”(SHALL NOT),“应当”(SHOULD),“不应”(SHOULD NOT),“推荐”(RECOMMENDED),“可以”(MAY)和“可选”(OPTIONAL)在这文档中将被用来描述。

1. 大纲

  • 代码必须遵守 PSR-1。

  • 代码必须使用4个空格的缩进,而不是制表符。

  • 一行代码长度不应硬性限制;软限制必须为120个字符;也应当是80个字符或者更少。

  • 在namespace声明下面必须有一个空行,并且use声明代码块下面也必须有一个空行。

  • 类的左花括号必须放到下一行,右花括号必须放在类主体的下一行。

  • 方法的左花括号必须放在下一行,右花括号必须放在方法主体下面。

  • 所有的属性和方法必须有可见性(译者注:Public, Protect, Private)声明;abstract和final声明必须在可见性之前;static声明必须在可见性之后。

  • 控制结构的关键词必须在后面有一个空格; 方法和函数不可有。

  • 控制结构的左花括号必须放在同一行,右花括号必须放在控制主体的下一行。

  • 控制结构的左括号后面不可有空格,右括号之前不可有空格。

1.1. 示例

本示例包含上面的一些规则简单展示:

	<?php
namespace Vendor\Package;

use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class Foo extends Bar implements FooInterface
{
    public function sampleFunction($a, $b = null)
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }

    final public static function bar()
    {
        // method body
    }
}

2. 概括

2.1 基础代码规范

代码必须遵守 PSR-1 的所有规则。

2.2 文件

所有的PHP文件必须使用Unix LF(换行)作为行结束符。

所有PHP文件必须以一个空行结束。

纯PHP代码的文件关闭标签?>必须省略

2.3. 行

行长度不可有硬限制。

行长度的软限制必须是120个字符;对于软限制,自动样式检查器必须警告但不可报错。

行实际长度不应超过80个字符;较长的行应当被拆分成多个不超过80个字符的后续行。

在非空行后面不可有空格。

空行可以用来改善可读性和区分相关的代码块。

一行不应多于一个语句。

2.4. 缩进

代码必须使用4个空格的缩进,并且不可使用制表符作为缩进。

注意:只用空格,不和制表符混合使用,将会对避免代码差异,补丁,历史和注解中的一些问题有帮助。使用空格还可以使调整细微的缩进来改进行间对齐变得非常简单。

2.5. 关键词和 True/False/Null

PHP keywords 必须使用小写。

PHP常量true, false和null必须使用小写。

3. Namespace和Use声明

如果存在,namespace声明之后必须有一个空行。

如果存在,所有的use声明必须放在namespace声明的下面。

一个use关键字必须只用于一个声明。

在use声明代码块后面必须有一个空行。

示例:

	<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

// ... additional PHP code ...

4. 类,属性和方法

术语“类”指所有的类,接口和特性(traits)。

4.1. 扩展和继承

一个类的extends和implements关键词必须和类名在同一行。

类的左花括号必须放在下面自成一行;右花括号必须放在类主体的后面自成一行。

	<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
    // constants, properties, methods
}

implements一个列表可以被拆分为多个有一次缩进的后续行。如果这么做,列表的第一项必须要放在下一行,并且每行必须只有一个接口。

	<?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. 属性

所有的属性必须声明可见性。

var关键词不可用来声明属性。

一个语句不可声明多个属性。

属性名称不应使用单个下划线作为前缀来表明保护或私有的可见性。

一个属性声明看起来应该下面这样的。

	<?php
namespace Vendor\Package;

class ClassName
{
    public $foo = null;
}

4.3. 方法

所有的方法必须声明可见性。

方法名不应只使用单个下划线来表明是保护或私有的可见性。

方法名在声明之后不可跟随一个空格。左花括号必须放在下面自成一行,并且右花括号必须放在方法主体的下面自成一行。左括号后面不可有空格,右括号前面不可有空格。

一个方法定义看来应该像下面这样。 注意括号,逗号,空格和花括号:

	<?php
namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

4.4. 方法参数

在参数列表中,逗号之前不可有空格,逗号之后必须要有一个空格。

方法中有默认值的参数必须放在参数列表的最后面。

	<?php
namespace Vendor\Package;

class ClassName
{
    public function foo($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

参数列表可以被分为多个有一次缩进的多个后续行。如果这么做,列表的第一项必须放在下一行,并且每行必须只放一个参数。

当参数列表被分为多行,右括号和左花括号必须夹带一个空格放在一起自成一行。

	<?php
namespace Vendor\Package;

class ClassName
{
    public function aVeryLongMethodName(
        ClassTypeHint $arg1,
        &$arg2,
        array $arg3 = []
    ) {
        // method body
    }
}

4.5. abstract,final和 static

如果存在,abstract和final声明必须放在可见性声明前面。

如果存在,static声明必须跟着可见性声明。

	<?php
namespace Vendor\Package;

abstract class ClassName
{
    protected static $foo;

    abstract protected function zim();

    final public static function bar()
    {
        // method body
    }
}

4.6. 调用方法和函数

要调用一个方法或函数,在方法或者函数名和左括号之间不可有空格,左括号之后不可有空格,右括号之前不可有空格。函数列表中,逗号之前不可有空格,逗号之后必须有一个空格。

	<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);

参数列表可以被拆分成多个有一个缩进的后续行。如果这么做,列表中的第一项必须放在下一行,并且每一行必须只有一个参数。

	<?php
$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);

5. 控制结构

对于控制结构的样式规则概括如下:

  • 控制结构关键词之后必须有一个空格
  • 左括号之后不可有空格
  • 右括号之前不可有空格
  • 在右括号和左花括号之间必须有一个空格
  • 代码主体必须有一次缩进
  • 右花括号必须主体的下一行

每个结构的主体必须被括在花括号里。这结构看上去更标准化,并且当加新行的时候可以减少引入错误的可能性。

5.1. if,elseif,else

一个if结构看起来应该像下面这样。注意括号,空格,花括号的位置;并且else和elseif和前一个主体的右花括号在同一行。

	<?php
if ($expr1) {
    // if body
} elseif ($expr2) {
    // elseif body
} else {
    // else body;
}

关键词elseif应该替代else if使用以保持所有的控制关键词像一个单词。

5.2. switch,case

一个switch结构看起来应该像下面这样。注意括号,空格和花括号。case语句必须从switch处缩进,并且break关键字(或其他中止关键字)必须和case主体缩进在同级。如果一个非空的case主体往下落空则必须有一个类似// no break的注释。

	<?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;
}

5.3. while,do while

一个while语句看起来应该像下面这样。注意括号,空格和花括号的位置。

	<?php
while ($expr) {
    // structure body
}

同样的,一个do while语句看起来应该像下面这样。注意括号,空格和花括号的位置。

	<?php
do {
    // structure body;
} while ($expr);

5.4. for

一个for语句看起来应该像下面这样。注意括号,空格和花括号的位置。

	<?php
for ($i = 0; $i < 10; $i++) {
    // for body
}

5.5. foreach

一个foreach语句看起来应该像下面这样。注意括号,空格和花括号的位置。

	<?php
foreach ($iterable as $key => $value) {
    // foreach body
}

5.6. try, catch

一个try catch语句看起来应该像下面这样。注意括号,空格和花括号的位置。

	<?php
try {
    // try body
} catch (FirstExceptionType $e) {
    // catch body
} catch (OtherExceptionType $e) {
    // catch body
}

6. 闭包

闭包在声明时function关键词之后必须有一个空格,并且use之前也需要一个空格。

左花括号必须在同一行,右花括号必须在主体的下一行。

参数列表和变量列表的左括号之后不可有空格,其右括号之前也不可有空格。

在参数列表和变量列表中,逗号之前不可有空格,逗号之后必须有空格。

闭包带默认值的参数必须放在参数列表后面。

一个闭包声明看起来应该像下面这样。注意括号,空格和花括号的位置。

	<?php
$closureWithArgs = function ($arg1, $arg2) {
    // body
};

$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
    // body
};

参数和变量列表可以被分成多个带一次缩进的后续行。如果这么做,列表的第一项必须放在下一行,并且一行必须只放一个参数或变量。

当最终列表(不管是参数还是变量)被分成多行,右括号和左花括号必须夹带一个空格放在一起自成一行。

下面是一个参数和变量列表被分割成多行的示例。

	<?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
};

注意如果在函数或者方法中把闭包作为一个参数调用,如上格式规则同样适用。

	<?php
$foo->bar(
    $arg1,
    function ($arg2) use ($var1) {
        // body
    },
    $arg3
);

7. 结论

在该指南中有很多风格的元素和做法有意被忽略掉。这些包括但不局限于:

  • 全局变量和全局常量的声明

  • 方法声明

  • 操作符和赋值

  • 行间对齐

  • 注释和文档块

  • 类名给你前缀和后缀

  • 最佳实践

以后的建议可以修改和扩展该指南以满足这些或其他风格的元素和实践