PSR代码规范

 更新时间:2020年4月28日 09:34  点击:2251

PHP推荐标准方面的概念,也就是PSR代码规范,从而掌握更加规范的编码方式。

一.暴露问题
当我们做PHP快速开发时,必然要选择各种合适我们当前项目的框架。但是,不同的框架开发年代、方式、思维都有所不同。导致的结果:不能与其它框架实现共享代码。比如A框架的某一个功能库很棒,但是现在用的B框架,移植的成本就变的很大。
所以,框架与框架之间并没有考虑过互相通信。对于开发者来说,这么做的效率非常的低。当大家意识到这种问题时,一个自发的组织PHP-FIG讨论如何提升框架之间的通信以及如何提升开发者的开发效率。进而制定了一系列的推荐规范,来加大代码之间的联系,改进框架之间的共享能力。

二.PSR诞生
PSR即:PHP推荐标准。目前通过审核的有PSR1-PSR4,还有最近的6和7。重点研究已经成熟的前四个,对于初学者来说,可以起到一个很好的代码规范作用。早些时候还有一个PSR0规范,但已经被PHP-FIG废弃从而被PSR4取代。

三.PSR1-4风格详解
PSR-1:基本的代码风格
PSR-1 是最为基础的 PHP 代码规范,也是最容易遵守的标准。

PSR-1 编码规范:
1.标签风格
必须严格的把PHP代码放在<?php ?>或<?= ?>标签中,不可以使用其它任何自定义的标签句法。

<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>//多行显示方式<?phpecho '多行';?>//单行显示方式<?='单行'?>

</body>
</html>

打印显示:
多行 单行

2.字符编码
PHP文件必须严格使用无BOM的UTF-8编码,在PHP专用的IDE上,设置的UTF-8编码基本都是无BOM的。在文本编辑器上,UTF-8编码有BOM和无BOM的选择。

3.副作用
在一个PHP文件中应该(并不强制)只定义新的声明(包括:类、函数或常量),或者只书写产品的逻辑操作。不应该同时具有两种,否则将会产生副作用。
换言之:不去在直接在执行的业务操作的文件中声明类、函数和常量等,而是通过包含文件将声明引入进来。也就是说,一个文件只做一件事,尽可能让它功能单一,而不要添加其它的&ldquo;副作用&rdquo;。
所以现在流行的开发模式为:程序入口+引导文件+自动加载+大量类库+开发者的MVC层。
可能产生副作用的有如下:
(1)生成输出;
(2)显现直接的加载文件:require或include;
(3)连接外部服务;
(4)修改ini配置;
(5)抛出错误或异常;
(6)修改全局或静态变量;
(7)读写文件等。

<?php//这个就是一个副作用require '1.php';//这又是一个副作用echo '<strong>';//函数function fnTest()
{//函数主体}

上面的代码,本身是一个函数创建的文件,却有引入文件和HTML输出的操作,产生了两个副作用。这种构建代码的方式,是不推荐的。

//判断函数是否存在,不属于副作用<?php//函数function fnTest()
{//函数主体}//这是一个主体,不属于副作用if (!function_exists('fnFoo')) {function fnFoo()
    {//函数主体    }
}

如果这个页面是声明函数相关的,附加了判断函数是否存在再创建函数,这种情况下,不算作&ldquo;副作用&rdquo;。

4.命名空间和类
(1)命名空间以及类的命名必须严格遵循PSR-4(自动加载控制器规范);
(2)每个类都独立为一个文件,且命名空间至少有一个层次:顶级的组织名称(vendorname);
(3)类的命名必须遵循大写开头的驼峰是规范,比如:Test;
(4)PHP5.3及以后的版本代码必须使用正式的命名空间。

//命名空间namespace Vendor\Model;//类class Test
{
}

关于常量:类的常量所有字符必须大写,词间用下划线分割。

//常量命名规范const PI = 3.14;const BATE_VERSION = '2.1.3';

关于属性:类的属性命名可以遵循(不做强制要求,但选择一种模式后,团队开发时必须统一规范风格):
(1)大写开头的驼峰式($WebName);
(2)小写开头的驼峰式($webName);
(3)下划线分割式($web_name);

//属性命名规范protected $WebName = '西西欢迎你们';

关于方法:方法名称必须严格符合小写开头的驼峰式命名规范。

//方法命名规范public function startApp()
{//方法主体}

举例:

<?php//命名空间namespace Psr\Model;//创建一个类Testclass Test
{//属性命名规范(受保护的)protected $WebName = '西西欢迎你们';protected $webName = 'xxx';protected $web_name = 'xxx';//常量命名规范const PI = 3.14;const BATE_VERSION = '2.1.3';//方法命名规范public function index()
    {

    }//方法主体public function startApp()
    {

    }
}

 

PSR-2:严格的代码风格
一.PSR-2概述
1.PSR-2其实是PSR-1的继承和扩展。和PSR-1不同的是,PSR-2更加的严格。当然,严格并不代表不容易,写到一定的量,就非常的好驾驭了。

二.PSR-2编码规范
1.编码准则
PHP代码必须严格符合PSR-1的所有规范。

2.文件准则
(1)PHP文件必须要以一个空白行作为结束;
(2)纯PHP代码文件必须省略最后的?>结束标签。

3.行准则
(1)代码每一行应该保持在80个字符以内;
(2)理论上一定不能超过120个字符;
(3)大于80个字符应该换成多行;
(4)非空行后面一定不可以有多余的空格符;
(5)空行可以有助于代码的可读性以及分块;
(6)每行一定不可以存在多条语句。

4.缩进准则
代码必须使用4个空格符的缩进,一定不可以使用tab键。这样可以避免不同环境或平台导致的代码差异,使之混乱。
注意:phpstorm等专用IDE会默认将tab键转换为4个空格符,所以,大胆敲tab键。具体测试,可以使用记事板测试便知。

5.关键字准则
(1)PHP所有的关键字必须全部小写;
(2)true、false和null也必须全部小写。

6.命名空间准则
(1)namespace声明后必须插入一个空白符;
(2)所有use必须在 namespace后声明;
(3)每条use声明语句必须只有一个use关键字;
(4)use声明语句块后必须要有一个空白行。

<?php
namespace Psr\Model;use Controller;use AbcAccess as Abc;//下面开始编写PHP代码

7.继承与实现准则
(1)关键字extends和implements必须写在类名称的同一行;
(2)类的开始花括号必须独占一开,结束的花括号也必须独占一行。

//继承和实现class MyPerson extend Person implements Action
{//类主体}

(3)implements的实现列表也可以分成多行,分成多行时,每个实现接口必须独立成行,包括第一个。

//实现多个接口class Person extends  Per implements\Action,\Abc,\Dec
{//类主体}

8.属性准则
(1)每个属性都必须添加访问修饰符;
(2)定不可以使用关键字var声明一个属性;
(3)每条语句一定不可以超过一个属性;
(4)不该使用下划线作为前缀区分是protected或private。

//标准的属性public $name = 'Mr.Wang';

9.方法准则
(1)所有方法都必须添加修饰符;
(2)不改使用下划线作为前缀,来区分protected或private;
(3)方法名后一定不可以有空格符,其开始花括号必须独占一行,结束花括号也必须独占一行;
(4)参数左括号后和右括号前,一定不可以有空格。

//标准方法public function run() 
{//方法主体}

10.参数准则
(1)参数列表中,每个逗号后面必须要有一个空格,而逗号前面不可以有空格;
(2)有默认值的参数,必须放在参数列表的末尾。

//标准参数public function run($key, $value, $arr = [])
{//方法主体}

(3)参数列表可以分列成多行,这样包括第一个参数在内的每个参数必须独立成行。
(4)拆分成多行的参数列表后,结束括号以及方法开始花括号必须写在同一行,中间用一个空格分隔。

//拆分参数public function run($key,$value,$arr = []
) {//方法主体}

11.abstract、final和static准则
需要添加abstract和final声明时,必须写在访问修饰符前面,而static则必须写在其后。

//抽象类<?php
namespace Psr\Model;
抽象类必须写在修饰符前面abstract class Computer
{//在修饰符后面protected static $mode;    //抽象写在在修饰符前面abstract public function run();    //在修饰符后面final public static function bar()
    {//方法主体    }
}

12.方法及函数调用准则
(1)方法及函数调用时,方法名或函数名与参数左括号之间一定不可以有空格,参数右括号前也一定不可以有空格。
(2)每个参数前一定不可以有空格,但其后必须有一个空格。

//标准调用$p->run($key, $value);
(3)参数可以分成多行,此时第一个参数在内的每一个都必须独立成行。//独立成行的参数$p->run($key,$value);

13.控制结构准则
(1)控制结构关键字后必须要有一个空格;
(2)左括号(后面一定不可以有空格;
(3)右括号)前面也一定不可以有空格;
(4)右括号)与开始花括号{之间必须要有一个空格;
(5)结构体主体必须要有一个缩进;
(6)结束花括号}必须在结构体主体后单独成行。
(7)每个结构体的主体都必须包含在成对的花括号之中,这能让结构体更加结构化,避免后期加入新行时出错的几率。

<?php//结构体if ($flag) {//结构体内部}

14.if、elseif和else
(1)else和elseif都与前面的结束花括号在同一行;
(2)elseif代替else if,让一个单词控制。

<?phpif ($flag) {//结构体内部} elseif ($flag2) {//elseif} else {//else}

15.switch和case
(1)case语句必须相对于switch进行一次缩进;
(2)break语句以及case内部的其它语句都必须相对case进行一次缩进;
(3)非空case直穿语句,主体里必须有类似//no break的注释。

<?phpswitch ($flag) {case 0:echo '开始阶段';break;case 1:echo '常规运行';//不需要breakcase 2:case 3:case 4:echo '结束阶段';break;default:echo '发生意外';break;
}

16.while和do while
while和do while结构体基本和if语句一致。

<?php//while标准格式while ($flag) {//}do {//} while ($flag);

17.for、foreach和try catch
这三种语法和if结构体规范要求基本一致。

<?php//for循环for ($i = 0; $i < 10; $i++) {///for结构体}//foreach遍历foreach ($array as $key => $value) {//foreach结构体}//try catchtry {//try} catch (Exception $e) {//catch}

18.闭包
(1)闭包声明时,关键字function后以及关键字use的前后都必须要有一个空格;
(2)开始花括号必须写在声明的同一行,结束花括号必须紧跟主体结束的下一行;
(3)参数列表和变量列表的左括号后以及右括号前,一定不可以有空格;
(4)参数和变量列表中,逗号前一定不可以有空格,而逗号后必须要有空格。

<?php//闭包$myFn = function ($arg1, $arg2) {//匿名函数代码};//闭包$myFn = function ($arg1, $arg2) use ($var1, $var2) {//匿名函数代码};//在分行显示时,和属性方法传参规则一样。$myFn = function ($arg1,$arg2) use($var1,$var2) {//匿名函数代码};

PSR-3:日志记录器接口;

一.PSR-3概述
PSR-3主要是定义一个日志接口,规定PHP日志记录器组件可以实现的方法。

二.PSR-3 编码规范
(1)必须包含一个实现Psr\Log\LoggerInterface(规范路径)接口的PHP类;
(2)需要实现九个方法。

//符合PSR-3的日志接口<?php//LoggerInterface.php路径namespace Psr\Log;/**
 * 日志记录实例 *
 * 日志信息变量 &mdash;&mdash; message,**必须** 是一个字符串或是实现了 __toString() 方法的对象。
 *
 * 日志信息变量中 **可以** 包含格式如 &ldquo;{foo}&rdquo; (代表 foo) 的占位符,
 * 它将会由上下文数组中键名为「foo」的键值替代。
 *
 * 上下文数组可以携带任意的数据,唯一的限制是,当它携带的是一个 exception 对象时,它的键名 **必须** 是 "exception"。 */interface LoggerInterface
{/**
     * 系统不可用
     *
     * @param string $message
     * @param array $context
     * @return null     */public function emergency($message, array $context = array());/**
     *  必须立刻采取行动
     *
     * 例如:在整个网站都垮掉了、数据库不可用了或者其他的情况下, **应该** 发送一条警报短信把你叫醒。
     *
     * @param string $message
     * @param array $context
     * @return null     */public function alert($message, array $context = array());/**
     * 紧急情况
     *
     * 例如:程序组件不可用或者出现非预期的异常。
     *
     * @param string $message
     * @param array $context
     * @return null     */public function critical($message, array $context = array());/**
     * 运行时出现的错误,不需要立刻采取行动,但必须记录下来以备检测。
     *
     * @param string $message
     * @param array $context
     * @return null     */public function error($message, array $context = array());/**
     * 出现非错误性的异常。
     *
     * 例如:使用了被弃用的API、错误地使用了API或者非预想的不必要错误。
     *
     * @param string $message
     * @param array $context
     * @return null     */public function warning($message, array $context = array());/**
     * 一般性重要的事件。
     *
     * @param string $message
     * @param array $context
     * @return null     */public function notice($message, array $context = array());/**
     * 重要事件
     *
     * 例如:用户登录和SQL记录。
     *
     * @param string $message
     * @param array $context
     * @return null     */public function info($message, array $context = array());/**
     * debug 详情
     *
     * @param string $message
     * @param array $context
     * @return null     */public function debug($message, array $context = array());/**
     * 任意等级的日志记录
     *
     * @param mixed $level
     * @param string $message
     * @param array $context
     * @return null     */public function log($level, $message, array $context = array());
}

然后可以创建一个具体实现这个接口的类,来编写日志管理类。比如编写一个Logger.php来实现这个接口(LoggerInterface)即可。

<?php//Logger.php路径namespace Model\Db;use Psr\Log\LoggerInterface;class Logger implements 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())
    {//debug 详情    }public function log($level, $message, array $context = array())
    {//任意等级的日志记录echo '日志等级为:' . $level . '<br>';//打印日志信息echo '日志信息为:' . $message . '<br>';
    }
}

test.php

<?phprequire 'Psr/Log/LoggerInterface.php';require 'Model/Db/Logger.php';$logger = new Model\Db\Logger();$logger->log('ERROR', '一条错误');

执行:http://192.168.3.62/Psr/test.php
日志等级为:ERROR
日志信息为:一条错误

目前来说没有编写细节方面的东西,而符合PSR-3规范的日志记录器,已经有相关组件可以直接使用了。比如:monolog。这个产品完全在LoggerInterface接口下开发,非常方便。


PSR-4:自动加载器
一.PSR-4 概述
PSR-4是关于由文件路径自动载入对应类的相关规范,在不要求改变代码的实现方式,只建议如何使用文件系统目录结构和PHP命名组织代码。

二.PSR-4编码规范
首先,先自行设计一个自动加载器,然后对照规范来检验。
目录结构如下:
1.加载文件:psr/Home/Model/Db/File.php

<?php//File.phpnamespace My\Think\Db;class File{public function run()
{echo 'model file running...';
}
}

2.执行文件:psr/auto.php

进行自动载入File.php文件

<?php//auto.phprequire '/Home/Model/Db/File.php';$file = new \My\Think\Db\File();$file->run();

执行:http://192.168.3.62/Psr/auto.php
model file running...
注意:命名空间最后的Db和类文件目录Db是一样的;而命名空间前缀和文件路径毫无关系。当然,你可以将命名空间和文件路径也完全对应起来,那样更加简单。

进行自动载入File.php文件

<?php
spl_autoload_register(function ($class) {//命名空间前缀$prefix = 'My\\think\\';////这个命名空间对应的目录(父路径)$base_dir = __DIR__.'/Home/Model/';//得到长度$len = strlen($prefix);//获取去掉前缀后的类名$relative_class = substr($class, $len);//完整类路径$path = $base_dir.$relative_class.'.php';//判断路径是否存在,如果存在引入过来if (file_exists($path)) {require $path;
    }
});//实例化$file = new \My\Think\Db\File();$file->run();

运行:http://192.168.3.62/Psr/auto.php
model file running...

一个完整的类名需具有以下结构:
\<命名空间>(\<子命名空间>)*\<类名>
(1)完整的类名必须要有一个顶级命名空间;
(2)完整的类名可以有一个或多个字命名空间;
(3)完整的类名必须有一个最终的类名;
(4)完整的类名中任意一部分中的下划线都是没有特殊含义的;
(5)完整的类名可以由大小写字母组成;
(6)所有类名都必须是大小写敏感的。

当根据完整的类名载入相应的文件
(1)完整的类名中,去掉最前面的命名空间分隔符,前面连续的一个或多个命名空间和子命名空间,作为「命名空间前缀」,其必须与至少一个「文件基目录」相对应;
(2)紧接命名空间前缀后的子命名空间必须与相应的「文件基目录」相匹配,其中的命名空间分隔符将作为目录分隔符。
(3)末尾的类名必须与对应的以.php 为后缀的文件同名。
(4)自动加载器(autoloader)的实现一定不可抛出异常、一定不可触发任一级别的错误信息以及不应该有返回值。

实际中,你根本不需要自行编写符合PSR-4规范的autoload自动加载器。可以使用composer来自动生成PSR-4自动加载器。

 

[!--infotagslink--]

相关文章

  • PSR代码规范

    PHP推荐标准方面的概念,也就是PSR代码规范,从而掌握更加规范的编码方式。一.暴露问题当我们做PHP快速开发时,必然要选择各种合适我们当前项目的框架。但是,不同的框架开发年代、方式、思维都有所不同。...2020-04-28
  • C++代码规范之命名规则

    以下是对C++中的命名规则进行了详细的分析介绍,需要的朋友可以参考下...2020-04-25
  • PHP符合PSR编程规范的实例分享

    好的代码书写习惯可以让人赏心悦目,下面这篇文章就给大家分享了PHP符合PSR编程规范的实例代码,有需要的朋友们可以参考借鉴,下面来一起看看吧。...2017-01-08