一、文件格式
1. 对于只含有 php 代码的文件,我们将在文件结尾处忽略掉 "?>" 。这是为了防止多余的空格或者其它字符影响到代码。
例如:
<?php
$foo = 'foo';
2. 缩进应该能够反映出代码的逻辑结果,尽量使用四个空格,禁止使用制表符TAB,因为这样能够保证有跨客户端编程器软件的灵活性。
例如:
if (1 == $x) {
$indented_code = 1;
if (1 == $new_line) {
$more_indented_code = 1;
}
}
3. 变量赋值必须保持相等间距和排列。
例如:
$variable = 'demo';
$var = 'demo2';
4. 每行代码长度应控制在80个字符以内,最长不超过120个字符。因为 linux 读入文件一般以80列为单位,就是说如果一行代码超过80个字符,那么系统将为此付出额外操作指令。这个虽然看起来是小问题,但是对于追求完美的程序员来说也是值得注意并遵守的规范。
5. 每行结尾不允许有多余的空格。
二、命名约定
1. 类文件都是以“.class.php“为后缀,且类文件名只允许字母,使用驼峰法命名,并且首字母大写,例如:DbMysql.class.php 。
2. 配置和函数等其他类库文件之外的文件一般是分别以“.inc.php“和”.php“为后缀,且文件名命名使用小写字母和下划线的方式,多个单词之间以下划线分隔,例如config.inc.php , common.php,install_function.php 。
3. 确保文件的命名和调用大小写一致,是由于在类Unix系统上面,对大小写是敏感的。
4. 类名和文件名一致(包括上面说的大小写一致),且类名只允许字母,例如 UserAction类的文件命名是UserAction.class.php, InfoModel类的文件名是InfoModel.class.php 。
5. 控制器类以Action为后缀,例如 UserAction、InfoAction ,模型类以Model为后缀,例如UserModel、InfoModel ,其他类也分别以相应分类为后缀,例如Service 、Widget。
6. 方法名只允许由字母组成,下划线是不允许的,首字母要小写,其后每个单词首字母要大写,即所谓的 “驼峰法命名” 规则,且越详细越好,应该能够描述清楚该方法的功能,例如switchModel、findPage。
7. 属性的命名只允许由字母组成,下划线是不允许的,首字母要小写,其后每个单词首字母要大写,即所谓的 “驼峰法命名” 规则,例如tablePrefix、tableName 。
8. 对于对象成员的访问,我们必须始终使用 “get” 和 “set” 方法。例如:
class Foo
{
protected $_testObj;
public function getTestObj()
return $this->_testObj;
}
public function setTestObj($testObj)
$this->testObj = $_testObj;
}
}
9. 当类成员方法被声明为 private 时,必须分别以双下划线 "__"为开头;被声明为 protected 时,必须分别以单下划线 "_" 为开头;一般情况下的方法不含下划线。例如 :
class Foo
{
private function __example()
// ...
}
protected function _example()
// ...
}
public function example()
// ...
}
}
10. 如果我们需要把一些经常使用的方法定义为全局函数,那么应该把它们以静态 (static) 的形式定义在类中。例如:
class Think
{
// ...
static public function autoload($classname)
{
// ...
}
}
11. 被声明为 private的类成员属性必须由双下划线 "__" 作为开头;被声明为 protected 的类成员属性必须由下划线 "_" 作为开头;而声明为 public 的成员属性则在任何时候都不允许含有下划线。
12. 函数的命名使用小写字母和下划线的方式,且越详细越好,应该能够描述清楚该函数的功能,例如 get_client_ip 。
13. 当方法或函数参数不一定需要被赋值的时候,用 "null" 来代替 "false" 作为函数参数的默认值,除非该参数是 boolean 值。
14. 变量只允许由小写字母和下划线组成,且建议用描述性的变量的命名,越详细越好,以至于像 $i 或 $n 等等都是不鼓励使用的。
15. 类中的常量 constant 和全局范围内常量define,只能由大写字母和下划线组成,各个单词之间以下划线分割。
16. boolean 值和 null 值都采用小写。
三、编码风格
1. php 代码必须以完整的形式来定界(<?php … ?>),即不要使用php 短标签(<? … ?>),且保证在关闭标签后不要有任何空格。
2. 当一个字符串是纯文本组成的时候(即不含有变量),则必须总是以单引号(')作为定界符。例如:
$a = 'Example String';
3. 变量替换中的变量只允许用 $+变量名 的形式。例如:
$greeting = "Hello $name, welcome back!"; // 允许
$greeting = "Hello {$name}, welcome back!"; // 允许
$greeting = "Hello ${name}, welcome back!"; // 不允许
当用点号 "." 连接各字符串的时候,字符串与点号间必须用一个空格隔开,且允许把它分割成多行以增强可读性。在这种情况下,点号 "." 必须与等于号 "=" 对齐。例如:
$sql = "SELECT `id`, `name` " . " FROM `people` "
. "WHERE `name` = 'Susan' "
. "ORDER BY `name` ASC ";
当用 array 类型符号来构造数组的时候,必须在每个逗号之后加上一个空格来增强可读性。例如:$sampleArray = array(1, 2, 3, 'Think', 'SNS');
4. 当使用 array 类型符声明关联数组的时候,我们鼓励把它分成多个行,只是我们必须同时保证每行的键与值的对齐,以保持美观。例如:
$sampleArray = array(
'firstKey' => 'firstValue',
'secondKey' => 'secondValue'
);
5. 大括号的开始必须在类名的下一行顶格。例如:
class Think
{
// ...
}
6. 类中的所有代码都必须用四个空格来进行缩进。
7. 每个 php 文件只允许声明一个类。在类文件里面写其它代码是允许的,但并不鼓励这样做。假如真要附加代码的话,必须用空行来分隔。
8. 任何类变量的声明都必须放在类顶部,先于任何函数的声明。
9. 不允许用 var 符号来声明变量,类成员变量必须以 private,protected 和 public 来声明。其次,把类成员声明为 public 而直接引用虽然是允许的,但通常更好的方法是使用 get 和 set 方法来访问类成员。
10. 方法必须总是用 private,protected 或者 public 来声明其作用域。
11. 静态 static 方法应该声明其作用域,且不应该再被声明为 private 私有,而应该为 protected 或者public ,如果只是不想被子类继承,则应该用 final 声明它们。
12. 函数或方法的初始大括号应该在函数声明的下一行顶格。例如:
function get_client_ip()
{
// …
}
13. 在函数或方法名与参数括号之间不允许出现多余的空格。例如:
function get_client_ip()
{
// …
}
14. 引用只允许定义在函数参数中,实时传递引用是禁止的。例如:
// 引用定义在函数参数-允许的
function defineRefInMethod(&$a)
{
$a = 'a';
}
defineRefInMethod($b);
echo $b; // 'a'
// 实时传递引用-禁止的
function callTimePassRef($a)
{
$a = 'a';
}
callTimePassRef(&$c);
echo $c; // 'a'
15. 函数或方法返回值不可以用括号包住,不然会降低可读性,而且假如以后函数修改为返回引用的话,这将会抛出一个异常。
16. 鼓励尽量使用类型提示,特别是在模块设计中。例如:
class Foo
{
public function foo(SomeInterface $object)
}
public function bar(array $options)
}
}
17. 函数和方法参数必须用逗号+空格来分隔。
18. 对于参数为数组的函数,参数中的数组应该分成多行以增强可读性。例如:
threeArguments(array(1, 2, 3), 2, 3);
threeArguments(array(1, 2, 3, 'Think',
'SNS', $a, $b, $c,
56.44, $d, 500), 2, 3);
19. 基于"if", "else"和"else if"的条件控制里,我们必须用空格间隔开语句和括号,大括号的开始 "{" 必须与条件控制语句位于同一行,结束 "}" 必须总是独占一行且顶格,控制流程内容必须用四个空格进行缩进,且不使用"elseif"。
if ($condition) {
// ...
} else if ($_condition) {
// ...
} else {
// ...
}
20. 在条件控制语句的条件括号内,必须用空格将操作符与其它元素隔开。如果遇到很长的逻辑判断,则鼓励用内嵌括号来分割各个逻辑。例如:
if (($a != 2) and ($b == 1)) {
$a = $b;
}
21. "switch" 条件控制语句中,必须用空格将待测参数与其它元素分隔开。例如:
switch ($num) {
// …
}
22. "switch" 语句的内容必须以四个空格缩进,"case" 条件控制的内容必须再加四个空格进行缩进。例如:
switch ($indentedSpaces) {
case 2:
echo "错误";
break;
case 4:
echo "正确";
break;
default:
break;
}
23. 在 "switch" 语句中应该总是包括 "default" 控制。
24. 有时候我们需要在 "case" 语境中省略掉 "break" 或 "return" ,这个时候我们必须为这些 "case" 语句加上 "// 此处无break" 注释。例如:
switch ($numPeople) {
case 1: // 此处无break
break;
default:
break;
}
强制性
- 一个完全标准的命名空间必须要有以下的格式结构
\<Vendor Name>\(<Namespace>\)*<Class Name>
- 命名空间必须有一个顶级的组织名称 ("Vendor Name").
- 命名空间中可以根据情况使用任意数量的子空间
- 从文件系统中加载源文件的时,命名空间中的分隔符将被映射为
DIRECTORY_SEPARATOR
- 命名空间中的类名中的
_
没有特殊含义,也将被作为DIRECTORY_SEPARATOR
对待. - 标准的命名空间和类从文件系统加载源文件时只需要加上
.php
后缀即可 - 组织名,空间名,类名都可以随意使用大小写英文字符的组合
示例
\Doctrine\Common\IsolatedClassLoader
=>/path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php
\Symfony\Core\Request
=>/path/to/project/lib/vendor/Symfony/Core/Request.php
\Zend\Acl
=>/path/to/project/lib/vendor/Zend/Acl.php
\Zend\Mail\Message
=>/path/to/project/lib/vendor/Zend/Mail/Message.php
命名空间和类名中的下划线
\namespace\package\Class_Name
=>/path/to/project/lib/vendor/namespace/package/Class/Name.php
\namespace\package_name\Class_Name
=>/path/to/project/lib/vendor/namespace/package_name/Class/Name.php
以上是我们为轻松实现自动加载特性设定的最低标准。你可以利用下面这个可以自动加载 PHP 5.3 类的SplClassLoader来测试你的代码是否符合以上这些标准。
实例
下面是一个函数实例简单展示如何使用上面建议的标准进行自动加载
<?php
function autoload($className)
{
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
}
SplClassLoader实现
下面的gist是一个可以按照上面建议的自动加载特性来加载类的SplClassLoader实例。这也是我们当前在PHP5.3中依据以上标准加载类时推荐的方。
基本代码规范
本节标准包含了成为标准代码所需要的基本元素,以确保开源出来的PHP代码之间有较高度的技术互用性。
在 RFC 2119中的特性关键词"必须"(MUST),“不可”(MUST NOT),“必要”(REQUIRED),“将会”(SHALL),“不会”(SHALL NOT),“应当”(SHOULD),“不应”(SHOULD NOT),“推荐”(RECOMMENDED),“可以”(MAY)和“可选”(OPTIONAL)在这文档中将被用来描述。
1. 大纲
-
源文件
必须
只使用<?php
和<?=
标签。 -
源文件中
必须
只使用不带BOM的UTF-8作为PHP代码。 -
源文件
应当
只声明符号(类,函数,常量等...)或者引起副作用(例如:生成输出,修改.ini配置等),但不应
同时做这两件事。 -
命名空间和类
必须
遵守 PSR-0。 -
类名
必须
使用骆驼式StudlyCaps
写法 (译者注:驼峰式的一种变种,后文将直接用StudlyCaps
表示)。 -
类中的常量
必须
使用全大写和下划线分隔符。 -
方法名
必须
使用驼峰式cameCase
写法(译者注:后文将直接用camelCase
表示)。
2. 文件
2.1. PHP标签
PHP代码必须
只使用长标签<?php ?>
或者短输出式<?= ?>
标签;它不可
使用其他的标签变种。
2.2. 字符编码
PHP代码必须
只使用不带BOM的UTF-8。
2.3. 副作用
一个文件应当
声明新符号 (类名,函数名,常量等)并且不产生副作用,或者应当
执行有副作用的逻辑,但不能同时做这两件事。
短语"副作用"意思是不直接执行逻辑的类,函数,常量等 仅包括文件
“副作用”包含但不局限于:生成输出,显式地使用require
或include
,连接外部服务,修改ini配置,触发错误或异常,修改全局或者静态变量,读取或修改文件等等
下面是一个既包含声明又有副作用的示例文件;即应避免的例子:
<?php
// side effect: change ini settings
ini_set('error_reporting', E_ALL);
// side effect: loads a file
include "file.php";
// side effect: generates output
echo "<html>\n";
// declaration
function foo()
{
// function body
}
下面是一个仅包含声明的示例文件;即需要提倡的例子:
<?php
// declaration
function foo()
{
// function body
}
// conditional declaration is *not* a side effect
if (! function_exists('bar')) {
function bar()
{
// function body
}
}
3. 命名空间和类名
命名空间和类名必须遵守 PSR-0.
这意味着每个类必须单独一个源文件,并且至少有一级命名空间:顶级的组织名。
类名必须使用骆驼式StudlyCaps
写法。
PHP5.3之后的代码必须
使用正式的命名空间例子:
<?php
// PHP 5.3 and later:
namespace Vendor\Model;
class Foo
{
}
PHP5.2.x之前的代码应当用伪命名空间Vendor_
作为类名的前缀
<?php
// PHP 5.2.x and earlier:
class Vendor_Model_Foo
{
}
4. 类常量,属性和方法
术语“类”指所有的类,接口和特性(traits)
4.1. 常量
类常量必须
使用全大写,并使用分隔符作为下划线。例子:
<?php
namespace Vendor\Model;
class Foo
{
const VERSION = '1.0';
const DATE_APPROVED = '2012-06-01';
}
4.2. 属性
本手册有意避免推荐使用$StulyCaps
,$camelCase
或者unser_score
作为属性名字
不管名称如何约定,它应当
在一个合理范围内保持一致。这个范围可能是组织层,包层,类层,方法层。
4.3. 方法
方法名必须用camelCase()
写法。
代码样式规范
本手册是 PSR-1基础代码规范的继承和扩展
本指南的意图是为了减少不同开发者在浏览代码时减少认知的差异。 为此列举一组如何格式化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. 结论
在该指南中有很多风格的元素和做法有意被忽略掉。这些包括但不局限于:
-
全局变量和全局常量的声明
-
方法声明
-
操作符和赋值
-
行间对齐
-
注释和文档块
-
类名给你前缀和后缀
-
最佳实践
以后的建议可以
修改和扩展该指南以满足这些或其他风格的元素和实践。
附录A 调查
为了写这个风格指南,我们采用了调查个项目以确定共同的做法。这个调查在这里供他人查看。
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. 调查说明
indent_type
:缩进类型。 tab
= "使用制表符",2
or 4
= "空格数量"
line_length_limit_soft
:行长度的“软”限制,用字符。 ?
= 不表示或者数字 no
意为不限制.
line_length_limit_hard
:行长度的"硬"限制,用字符。 ?
= 不表示或者数字, no
意为不限制.
class_names
:类名如何命名 lower
= 只是小写, lower_under
= 小写加下划线, studly
= 骆驼型.
class_brace_line
:类的左花括号是放在同(same
)一行还是在下(next
)一行?
constant_names
:类常量如何命名?upper
= 大写加下划线分隔符。
true_false_null
:全校写或者全大写?
method_names
:方法名如何命名?camel
= 驼峰式
, lower_under
= 小写加下划线分隔符。
method_brace_line
:方法的左花括号在同(same
)一行还是在下(next
)一行?
control_brace_line
:控制结构的左花括号在同(same
)一行还是在下(next
)一行?
control_space_after
:控制结构关键词后是否有空格?
always_use_control_braces
:控制结构总是使用花括号?
else_elseif_line
:当使用else
和elseif
,是否放在同(same
)一行还是在下(next
)一行?
case_break_indent_from_switch
:case
和break
分别从swith
语句处缩进多少次?
function_space_after
:函数调用的函数名和左括号是否有空格?
closing_php_tag_required
:如过是纯PHP文件,关闭标签?>
是否需要?
line_endings
:使用何种的行结束符?
static_or_visibility_first
:在定义方法的时候static
和可见性谁在前面?
control_space_parens
:在控制结构表达式中,左括号后面和右括号前面是否要有一个空格?yes
= if ( $expr )
, no
= if ($expr)
.
blank_line_after_php
:PHP的开始标签后面是否需要一个空行?
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
日志接口
本文档用来描述日志类库的通用接口。
主要目标是让类库获得一个Psr\Log\LoggerInterface
对象并且使用一个简单通用的方式来写日志。有自定义需求的框架和CMS可以
根据情况扩展这个接口,但应当
保持和该文档的兼容性,这将确保使用第三方库和应用能统一的写应用日志。
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD","SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to beinterpreted as described in RFC 2119.
关键词实现者
在这个文档被解释为:在日志相关的库和框架实现LoggerInterface
接口的人。用这些实现的人都被称作用户
。
1. 规范
1.1 基础
-
LoggerInterface
暴露八个接口用来记录八个等级(debug, info, notice, warning, error, critical, alert, emergency)的日志。 -
第九个方法是
log
,接受日志等级作为第一个参数。用一个日志等级常量来调用这个方法的结果必须
和调用具体等级方法的一致。如果具体的实现不知道传入的不按规范的等级来调用这个方法必须
抛出一个Psr\Log\InvalidArgumentException
。用户不应
自定义一个当前不支持的未知等级。
1.2 消息
-
每个方法都接受字符串,或者有
__toString
方法的对象作为消息。实现者可以对传入的对象有特殊的处理。如果不是,实现者必须
将它转换成字符串。 -
消息
可以
包含可以
被上下文数组的数值替换的占位符。占位符名字
必须
和上下文数组键名对应。占位符名字
必须
使用使用一对花括号为分隔。在占位符和分隔符之间不能
有任何空格。占位符名字
应该
由A-Z
,a-z
,0-9
,下划线_
和句号.
。其它的字符作为以后占位符规范的保留。实现者可以使用占位符来实现不同的转义和翻译日志成文。用户在不知道上下文数据是什么的时候
不应
提前转义占位符。下面提供一个占位符替换的例子,仅作为参考:
/** * Interpolates context values into the message placeholders. */ function interpolate($message, array $context = array()) { // build a replacement array with braces around the context keys $replace = array(); foreach ($context as $key => $val) { $replace['{' . $key . '}'] = $val; } // interpolate replacement values into the message and return return strtr($message, $replace); } // a message with brace-delimited placeholder names $message = "User {username} created"; // a context array of placeholder names => replacement values $context = array('username' => 'bolivar'); // echoes "Username bolivar created" echo interpolate($message, $context);
1.3 上下文
-
每个方法接受一个数组作为上下文数据,用来存储不适合在字符串中填充的信息。数组可以包括任何东西。实现者
必须
确保他们对上下文数据足够的掌控。在上下文中一个给定值不可
抛出一个异常,也不可
产生任何PHP错误,警告或者提醒。 -
如果在上下文中传入了一个
异常
对象,它必须以exception
作为键名。记录异常轨迹是通用的模式,如果日志底层支持这样也是可以被允许的。实现者在使用它之前必须
验证exception
的键值是不是一个异常
对象,因为它可以
允许是任何东西。
1.4 助手类和接口
-
Psr\Log\AbstractLogger
类让你非常简单的实现和扩展LoggerInterface
接口以实现通用的log
方法。其他八个方法将会把消息和上下文转发给它。 -
类似的,使用
Psr\Log\LoggerTrait
只需要你实现通用的log
方法。记住traits不能实现接口前,你依然需要implement LoggerInterface
。 -
Psr\Log\NullLogger
是和接口一个提供的。它可以
为使用接口的用户提供一个后备的“黑洞”。如果上下文数据非常重要,这不失为一个记录日志更好的办法。 -
Psr\Log\LoggerAwareInterface
只有一个setLogger(LoggerInterface $logger)
方法可以用来随意设置一个日志记录器。 -
Psr\Log\LoggerAwareTrait
trait可以更简单的实现等价于接口。通过它可以访问到$this->logger
。 -
Psr\Log\LogLevel
类拥有八个等级的常量。
2. 包
作为psr/log 的一部分,提供接口和相关异常类的一些描述以及一些测试单元用来验证你的实现。
3. Psr\Log\LoggerInterface
<?php
namespace Psr\Log;
/**
* Describes a logger instance
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data, the only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*/
interface LoggerInterface
{
/**
* System is unusable.
*
* @param string $message
* @param array $context
* @return null
*/
public function emergency($message, array $context = array());
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
* @return null
*/
public function alert($message, array $context = array());
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
* @return null
*/
public function critical($message, array $context = array());
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
* @return null
*/
public function error($message, array $context = array());
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
* @return null
*/
public function warning($message, array $context = array());
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
* @return null
*/
public function notice($message, array $context = array());
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
* @return null
*/
public function info($message, array $context = array());
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
* @return null
*/
public function debug($message, array $context = array());
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
* @return null
*/
public function log($level, $message, array $context = array());
}
4. Psr\Log\LoggerAwareInterface
<?php
namespace Psr\Log;
/**
* Describes a logger-aware instance
*/
interface LoggerAwareInterface
{
/**
* Sets a logger instance on the object
*
* @param LoggerInterface $logger
* @return null
*/
public function setLogger(LoggerInterface $logger);
}
5. Psr\Log\LogLevel
<?php
namespace Psr\Log;
/**
* Describes log levels
*/
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}