PSR 2 编码风格指南

本篇规范是 PSR-1 基本代码规范的继承与补充

本规范希望通过制定一系列规范化 PHP 代码的规则,以减少在浏览不同作者的代码时,因代码风格的不同而造成不便

当多名程序员在多个项目中合作时,就需要一个共同的编码规范, 而本文中的风格规范源自于多个不同项目代码风格的共同特性, 因此,本规范的价值在于我们都遵循这个编码风格,而不是在于它本身

本篇规范中的 必须,不得,需要,应,不应,应该,不应该,推荐,可能 和 可选 等词按照 RFC 2119 中的描述进行解释

规范

  1. 代码 必须 遵循 PSR-1 中的编码规范

  2. 代码 必须 使用 4 个空格符进行缩进,而不是使用制表符 ( \t ) 或者 「 Tab 键 」

    还是可以使用 Tab 键,只要设置将 Tab 键转换成 4 个空格即可

  3. 每行的字符数 应该 软性保持在 80 个之内,理论上 一定不能 多于 120 个字符,且 一定不可 有硬性限制

  4. 每个 namespace 命名空间声明语句和 use 声明语句块后面,必须 插入一个空白行

  5. 代码块开始的花括号( {必须 写在函数声明或类声明后自成一行,结束花括号( } )也 必须 写在函数主体或类主体后自成一行

  6. 类的属性和方法 必须 添加访问修饰符 ( privateprotected 以及 public ) ,abstract 以及 final 必须 声明在访问修饰符之前,而 static 必须 声明在访问修饰符之后

  7. 控制结构的关键字后 必须 要有一个空格符,而调用方法或函数时则 一定不可

  8. 控制结构的开始花括号( {必须 写在声明的同一行,而结束花括号( } ) 必须 写在主体后自成一行

  9. 控制结构的开始左括号后和结束右括号前 一定不可 有空格

1.1 范例

本范例的代码将作为下文规则的快速概览

<?php

namespace Vendor\Package;

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

class Foo extends Bar implements FooInterface
{
    public function sampleMethod($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 (linefeed) 作为行的结束符

所有 PHP 文件 必须 以空白行结尾

纯 PHP 文件 必须 省略最后的 ?> 结束标签

2.3. 行 行的长度 一定不可 有硬性的约束。

2.3. 行

行的长度 一定不可 有硬性的限制

软性的长度约束 必须 要限制在 120 个字符以内,若超过此长度,带代码规范检查的编辑器 必须 要发出警告,不过 一定不可 发出错误提示

每行 不该 多于 80 个字符,大于 80 字符的行 应该 折成多行

非空白行后 一定不可 有多余的空白符

空白行 可以 有助于改进阅读和区分代码块

每行 一定不能 多于一条语句

2.4. 缩进

代码必须使用 4 个空格缩进,且 一定不能 使用制表符 ( \t )

注: 仅使用空格,而不是混用空格和 tab 键,能够避免在查看代码差异,打补丁,查看提交历史,以及进行注解时产生问题
使用空格也使得代码对齐更轻松

2.5. 关键字 和 True / False / Null

PHP 的 关键字 必须 使用小写形式

PHP 中的常量 true, false, 还有 null 必须 使用小写形式

命名空间和使用声明

  1. namespace 命名空间声明语句之后必须添加一个空白行

  2. 所有的 use 声明必须在 namespace 声明之后

  3. 每一个 use 关键字 必须 且只能用于引用一个声明

  4. use 语句块之后,必须添加一个空白行

范例

<?php
namespace Vendor\Package;

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

// ... 其它 PHP 代码 ...

4. 类 、属性、 和 方法

此处的 「类」泛指所有的 「 class 类 」、「 接口 」以及「 traits 可复用代码块 」

4.1. 继承 与 实现

  1. 关键词 extendsimplements 必须 写在类名称的同一行

  2. 类的开始花括号 必须 独占一行,结束花括号也 必须 在类的主体后独占一行

范例

<?php
namespace Vendor\Package;

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

class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
    // 常量, 属性, 方法
}

implements 关键字的实现接口列表 可以 分成多行,一旦这么做,那么每个实现接口名称都 必须 分开独立成行,包括第一个

<?php
namespace Vendor\Package;

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

class ClassName extends ParentClass implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // 常量, 属性, 方法
}

4.2. 属性

  1. 所有的属性都 必须 添加访问修饰符

  2. 一定不可 使用 var 关键字来声明一个属性

  3. 每条语句 一定不可 多于一个属性的声明

  4. 属性名 不应该 使用下划线 ( _ ) 作为前缀来区分是 protected or private

范例

以下是属性声明的一个范例

<?php
namespace Vendor\Package;

class ClassName
{
    public $foo = null;
}

4.3. 方法

  1. 所有的方法都 必须 添加访问修饰符

  2. 方法名 不应该 使用下划线 ( _ ) 作为前缀来区分是 protectedprivate

  3. 声明方法时,方法名和左括号 ( ( ) 之间一定 不能 有空格

  4. 开始花括号 ( { ) 必须 独占一行,且后面不能有空格

  5. 结束花括号 ( } ) 必须 独占一行,且前面不能有空格

以下是方法声明的一个范例

留意其括号、逗号、空格以及花括号的位置

<?php
namespace Vendor\Package;

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

4.4. 方法的参数

  1. 参数列表中,逗号 ( , ) 之前 一定不可 有空格,逗号之后 必须 且只有有一个空格

  2. 参数列表中,有默认值的参数 必须 放在参数列表的末尾

<?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 关键字

  1. 当需要添加 abstractfinal 声明时,abstractfinal 必须 写在访问修饰符 ( publicprivateprotected ) 之前

  2. 当需要添加 static 声明时,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. 控制结构

控制结构的基本规范如下

  1. 控制结构关键字的后面 必须 有一个空格
  2. 左括号 ( ( ) 之后 一定不能 有空格
  3. 右括号 ( ) ) 之前 一定不能 有空格
  4. 右括号 ( ) ) 与左花括号 ( { ) 之间 必须 有一个空格
  5. 控制结构代码块 必须 且只能缩进一次
  6. 结束花括号 ( } ) 必须 在结构主体之后独占一行

每个控制结构的主体 必须 放在一对花括号 ( {} ) 中,这样就能够减少插入新行时出错的可能性

5.1. ifelseifelse

关键字 elseif 必须 使用 else if 代替,这样所有的控制结构关键词都是一个单独的单词

下面的代码是一个标准的 if 控制结构

留意「括号」、「空格」以及「花括号」的位置

注意 elseelse if 都与前面的结束花括号在同一行

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

5.2. switch, case

  1. case 语句 必须 相对 switch 进行一次缩进
  2. break 语句以及 case 内的其它语句都 必须 相对 case 进行一次缩进
  3. 如果存在非空的 case 直穿语句,主体里 必须 有类似 // no break 的注释

下面的代码是一个标准的 switch 控制结构

留意「括号」、「空格」以及「花括号」的位置

<?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. 闭包 ( Closures )

  1. 声明闭包时,关键词 function 后以及关键词 use 的前后都 必须 要有一个空格

  2. 开始花括号 必须 写在声明的同一行,结束花括号 必须 紧跟主体结束的下一行,独自成行

  3. 参数列表和变量列表的左括号后以及右括号前,一定不可 有空格

  4. 参数和变量列表中,逗号前 一定不可 有空格,而逗号后 必须 要有空格

  5. 闭包中有默认值的参数 必须 放到列表的后面

下面的代码是一个符合标准的闭包声明

注意留意「括号」、「空格」以及「花括号」的位置

<?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. 总结

本指南故意删除了许多风格与实践, 它们包括但不限于:

  1. 全局变量和常量的声明

  2. 函数声明

  3. 运算符与赋值

  4. 行间对齐

  5. 注释与文档描述块

  6. 类名前缀与后缀

  7. 最佳实践

本指南将来的修订和扩展 可能 会弥补上述或其他风格与最佳实践

附录 A. 调研

撰写这篇风格指南的过程中,FIG 团队对众多的成员做了一份调研,用于寻找常见的风格

在此保留一份数据,以供后查

A.1. 调研数据

url,http://www.horde.org/apps/horde/docs/CODING_STANDARDS,http://pear.php.net/manual/en/standards.php,http://solarphp.com/manual/appendix-standards.style,http://framework.zend.com/manual/en/coding-standard.html,http://symfony.com/doc/2.0/contributing/code/standards.html,http://www.ppi.io/docs/coding-standards.html,https://github.com/ezsystems/ezp-next/wiki/codingstandards,http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html,https://github.com/UnionOfRAD/lithium/wiki/Spec%3A-Coding,http://drupal.org/coding-standards,http://code.google.com/p/sabredav/,http://area51.phpbb.com/docs/31x/coding-guidelines.html,https://docs.google.com/a/zikula.org/document/edit?authkey=CPCU0Us&hgd=1&id=1fcqb93Sn-hR9c0mkN6m_tyWnmEvoswKBtSc0tKkZmJA,http://www.chisimba.com,n/a,https://github.com/Respect/project-info/blob/master/coding-standards-sample.php,n/a,Object Calisthenics for PHP,http://doc.nette.org/en/coding-standard,http://flow3.typo3.org,https://github.com/propelorm/Propel2/wiki/Coding-Standards,http://developer.joomla.org/coding-standards.html
voting,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,no,no,?,yes,no,yes
indent_type,4,4,4,4,4,tab,4,tab,tab,2,4,tab,4,4,4,4,4,4,tab,tab,4,tab
line_length_limit_soft,75,75,75,75,no,85,120,120,80,80,80,no,100,80,80,?,?,120,80,120,no,150
line_length_limit_hard,85,85,85,85,no,no,no,no,100,?,no,no,no,100,100,?,120,120,no,no,no,no
class_names,studly,studly,studly,studly,studly,studly,studly,studly,studly,studly,studly,lower_under,studly,lower,studly,studly,studly,studly,?,studly,studly,studly
class_brace_line,next,next,next,next,next,same,next,same,same,same,same,next,next,next,next,next,next,next,next,same,next,next
constant_names,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper,upper
true_false_null,lower,lower,lower,lower,lower,lower,lower,lower,lower,upper,lower,lower,lower,upper,lower,lower,lower,lower,lower,upper,lower,lower
method_names,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel,lower_under,camel,camel,camel,camel,camel,camel,camel,camel,camel,camel
method_brace_line,next,next,next,next,next,same,next,same,same,same,same,next,next,same,next,next,next,next,next,same,next,next
control_brace_line,same,same,same,same,same,same,next,same,same,same,same,next,same,same,next,same,same,same,same,same,same,next
control_space_after,yes,yes,yes,yes,yes,no,yes,yes,yes,yes,no,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes
always_use_control_braces,yes,yes,yes,yes,yes,yes,no,yes,yes,yes,no,yes,yes,yes,yes,no,yes,yes,yes,yes,yes,yes
else_elseif_line,same,same,same,same,same,same,next,same,same,next,same,next,same,next,next,same,same,same,same,same,same,next
case_break_indent_from_switch,0/1,0/1,0/1,1/2,1/2,1/2,1/2,1/1,1/1,1/2,1/2,1/1,1/2,1/2,1/2,1/2,1/2,1/2,0/1,1/1,1/2,1/2
function_space_after,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no
closing_php_tag_required,no,no,no,no,no,no,no,no,yes,no,no,no,no,yes,no,no,no,no,no,yes,no,no
line_endings,LF,LF,LF,LF,LF,LF,LF,LF,?,LF,?,LF,LF,LF,LF,?,,LF,?,LF,LF,LF
static_or_visibility_first,static,?,static,either,either,either,visibility,visibility,visibility,either,static,either,?,visibility,?,?,either,either,visibility,visibility,static,?
control_space_parens,no,no,no,no,no,no,yes,no,no,no,no,no,no,yes,?,no,no,no,no,no,no,no
blank_line_after_php,no,no,no,no,yes,no,no,no,no,yes,yes,no,no,yes,?,yes,yes,no,yes,no,yes,no
class_method_control_brace,next/next/same,next/next/same,next/next/same,next/next/same,next/next/same,same/same/same,next/next/next,same/same/same,same/same/same,same/same/same,same/same/same,next/next/next,next/next/same,next/same/same,next/next/next,next/next/same,next/next/same,next/next/same,next/next/same,same/same/same,next/next/same,next/next/next

A.2. 调研说明

  1. indent_type

    缩进风格

    tab = "Use a tab", 2 or 4 = "number of spaces"

  2. line_length_limit_soft

    「 soft 」软换行字符限制

    ? = 不可辨比或没有回复, no 表示无限制

  3. line_length_limit_hard

    「 hand 」 硬换行字符限制

    ? = 不可辨比或没有回复, no 表示无限制

  4. class_names

    类如何命名

    lower = 全部字母小写形式

    lower_under = 小写字母形式,词之间使用下划线 ( _ ) 分隔

    studly = 首字母大写的驼峰命名法

  5. class_brace_line

    声明类时 左花括号的位置

    same = 和类名放在同一行

    next = 类名之后单独成行

  6. constant_names

    常量命名方式

    upper = 所有字母大写且使用下划线分隔每个单词

  7. true_false_null

    truefalsenull 的书写形式

    lower = true, falsenull 几个关键字都小写

    upper = true, falsenull 几个关键字都大写

  8. method_names

    方法名命名方式

    camel = camelCase 驼峰命名法

    lower_under = 所有字母下写且单词之间使用下划线分隔

  9. method_brace_line

    方法声明中开始大括号的位置

    same = 和方法名在同一行

    next = 方法名之后单独成行

  10. control_brace_line

    控制语句大括号的位置

    same = 和控制语句关键词同一行

    next = 控制语句关键词之后单独成一行

  11. control_space_after

    控制结构关键词之后是否有一个空格

  12. always_use_control_braces

    控制语句是否始终都添加花括号

    如果控制结构只有一条语句,是可以不用添加大括号的

  13. else_elseif_line

    当使用 elseelseif 时,是否单独一行

    same = 和结束花括号 ( } ) 同一行

    next = 结束花括号之后单独成行

  14. case_break_indent_from_switch

    casebreak 语句相比于 switch 的缩进次数

  15. function_space_after

    调用函数时,函数名和左小括号 ( 之间是否有一个空格

  16. closing_php_tag_required

    纯 PHP 文件,是否添加 PHP ?> 标签

  17. line_endings

    使用哪种类型的换行符

  18. static_or_visibility_first

    声明方法时,是把 static 写在开头还是将访问控制符写在开头

18 . control_space_parens

使用控制结构表达式时,是否在小括号之间添加空格

 `yes` = `if ( $expr )`

 `no` = `if ($expr)`
  1. blank_line_after_php

    <?php 标签之后是否有一个空白行

  2. class_method_control_brace

    类 、方法 和 控制接口中的开始花括号的位置

A.3. 调研结果

indent_type:
    tab: 7
    2: 1
    4: 14
line_length_limit_soft:
    ?: 2
    no: 3
    75: 4
    80: 6
    85: 1
    100: 1
    120: 4
    150: 1
line_length_limit_hard:
    ?: 2
    no: 11
    85: 4
    100: 3
    120: 2
class_names:
    ?: 1
    lower: 1
    lower_under: 1
    studly: 19
class_brace_line:
    next: 16
    same: 6
constant_names:
    upper: 22
true_false_null:
    lower: 19
    upper: 3
method_names:
    camel: 21
    lower_under: 1
method_brace_line:
    next: 15
    same: 7
control_brace_line:
    next: 4
    same: 18
control_space_after:
    no: 2
    yes: 20
always_use_control_braces:
    no: 3
    yes: 19
else_elseif_line:
    next: 6
    same: 16
case_break_indent_from_switch:
    0/1: 4
    1/1: 4
    1/2: 14
function_space_after:
    no: 22
closing_php_tag_required:
    no: 19
    yes: 3
line_endings:
    ?: 5
    LF: 17
static_or_visibility_first:
    ?: 5
    either: 7
    static: 4
    visibility: 6
control_space_parens:
    ?: 1
    no: 19
    yes: 2
blank_line_after_php:
    ?: 1
    no: 13
    yes: 8
class_method_control_brace:
    next/next/next: 4
    next/next/same: 11
    next/same/same: 1
    same/same/same: 6

PHP 标准规范

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.