/ php

ModernPHP PSR

简介

PSR是PHP Standards Recommendation(PHP推荐标准)的简称。到目前为止,有四个被广泛认同的标准:

也许你还见过PSR-0(自动加载标准),PHP-FIG废弃了该推荐规范,用PSR-4替代了它。

PSR-1

php标签

必须把PHP代码放在标签中。

编码

必须使用UTF-8 without BOM的编码。

目的性

一个PHP文件可以定义符号(类,性状,函数和常量等),或者执行副作用的操作(例如,生成结果或者处理数据),但是不能同时做这两件事。

自动加载

PHP命名空间和类必须遵守PSR-4自动加载器标准。

类名

PHP类名必须使用首字母大写的驼峰命名方式,比如UserData。

常量名

PHP常量的名称必须全部使用大写字母,必要的话可以使用下划线连接单词,例如PAGE_SIZE。

方法名

PHP方法名必须使用首字母小写的驼峰命名方式,比如getUserInfo。

PSR-2

PSR-2相对于PSR-1的代码风格更加严格。

贯彻PSR-1

使用PSR-2代码风格之前必须先贯彻PSR-1。

缩进

这个话题就很热门了,代码的缩进一直分为两个阵营:tab键阵营,多空格阵营。《硅谷》中有一集男女两名程序员正一边编程一边约会,小伙子忍受不了姑娘使用空格键缩进,认为Tab键更节省文件体积,最后愤然离去,声称绝对不会和用空格键缩进的人滚床单,以免孩子面临艰难的人生抉择……可见这个问题在程序员中是比较突出和常见的,PSR-2推荐规范要求PHP代码使用4个空格的缩进。

文件代码行

PHP文件必须使用UNIX风格的换行符(LF),最后要有一个空行,而且不能使用PHP关闭标签?>。PHP每行代码不能超过80个字符,至少不能超过120个字符。每行末尾不能有空格。

关键字

PHP关键字应该使用小写字母。

命名空间

每个命名空间声明语句后必须跟着一个空行,类似的,使用use导入命名空间的语句后面也要加一个空行。下面是一个示例:

<php
namespace My\Component;
    
use Symfony\Components\HttpFoundation\Request;
use Symfony\Components\HttpFoundation\Response;
 
class App 
{
    // ...
}

PSR-2要求类定义体的起始括号应该在类名之后新起一行写,结束括号必须在定义体后新起一行,就像上面那个例子一样。如果类扩展其他类或者实现接口,extends和implements关键字必须和类名同一行。

方法

方法定义体的括号位置应该可类定义的括号一样。方法的参数需要注意:起始圆括号之后和结束圆括号之前都没有空格,方法的每个参数后面都有一个逗号和空格。

<php
namespace Project;

class App
{
    public function index($id = 1, $name)
    {
        // ...
    }
}

可见性

类中的每个属性和方法都要声明可见性,即public、protected或者private,来决定类的内部和外部如何访问这些属性和方法。请不要再对属性使用var关键字,在私有方法前加下划线。如果雷属性或方法声明为abstract或final,这两个限定符必须放在可见性关键字之前。static限定符应该放在可见性关键字之后。

<?php
namespace Project;

class App
{
    public static $startCount = '1.0';

    protected function __construct()
    {
        static::$startCount++;
    }
}

控制结构

所有控制结构关键字后面都要有一个空格。控制结构关键字包括:if、elseif、else、switch、case、while、do while、for、foreach、try和catch。如果控制结构关键字后面有一对圆括号,起始圆括号之后和结束圆括号之前都没有空格。与类和方法的定义体不同,空间结构关键字后面的起始括号应该和控制结构关键字在同一行。

<?php
$num = 0;
$flag = false;

if ($flag === false) {
    while ($num &lt; 10) {
        $num++;
    }
}

PSR-3

这个推荐规范讲的是一个接口,规定PHP日志记录器组件可以实现的方法。

符合PSR-3推荐规范的PHP日志记录,必须包含一个实现Psr\Log\LoggerInterface接口的PHP类。PSR-3接口复用了RFC-5424系统日志协议,规定要实现9个方法。

<?php
namespace Psr\Log;

interface LoggerInterface
{
    public function emergency($message, array $context = array());
    public function alert($message, array $context = array());
    public function critical($message, array $context = array());
    public function error($message, array $context = array());
    public function warning($message, array $context = array());
    public function notice($message, array $context = array());
    public function info($message, array $context = array());
    public function debug($message, array $context = array());
    public function log($level, $message, array $context = array());
}

每个方法对应RFC 5424协议的一个日志级别,而且都接受两个参数。第一个参数$message必须是一个字符串,或者是一个有__toString()方法的对象。第二个参数$context是可选的,这是一个数组,提供用于替换第一个参数中占位符的值。

$context参数用于构造复杂的日志消息。消息文本中可以使用占位符,例如{placeholder_name}。占位符由{,占位符名称和}组成,不能包含空格。$context参数的值是一个关联数组,键是占位符的名称,对应的值用于替换消息文本中的占位符。

PSR-4

PSR-4的精髓是把命名空间的前缀和文件系统中的目录对应起来。下面是一个PSR-4规范的自动加载器的例子:

<?php
/**
 * @param string $class 完全限定的类名
 * @return void
 */
spl_autoload(function ($class) {
	// 项目命名空间前缀
	$prefix = 'Foo\\Bar\\';
	
	// 命名空间对应的基目录
	$base_dir = __DIR__ . '/src/';
	
	// 比较传入的类名是否使用命名空间的前缀
	$len = strlen($prefix);
	if(strncmp($prefix, $class, $len) !== 0) {
		return;
	}
	
	// 获取去除前缀的类名
	$relative_class = substr($class, $len);
	
	// 获取类的地址
	$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
	
	// 导入文件
	if(file_exists($file) {
		require $file;
	}
	
});

ModernPHP 系列全集:传送门