PSR代码规范
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文件中应该(并不强制)只定义新的声明(包括:类、函数或常量),或者只书写产品的逻辑操作。不应该同时具有两种,否则将会产生副作用。
换言之:不去在直接在执行的业务操作的文件中声明类、函数和常量等,而是通过包含文件将声明引入进来。也就是说,一个文件只做一件事,尽可能让它功能单一,而不要添加其它的“副作用”。
所以现在流行的开发模式为:程序入口+引导文件+自动加载+大量类库+开发者的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() {//函数主体 } }
如果这个页面是声明函数相关的,附加了判断函数是否存在再创建函数,这种情况下,不算作“副作用”。
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;/** * 日志记录实例 * * 日志信息变量 —— message,**必须** 是一个字符串或是实现了 __toString() 方法的对象。 * * 日志信息变量中 **可以** 包含格式如 “{foo}” (代表 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自动加载器。
相关文章
- PHP推荐标准方面的概念,也就是PSR代码规范,从而掌握更加规范的编码方式。一.暴露问题当我们做PHP快速开发时,必然要选择各种合适我们当前项目的框架。但是,不同的框架开发年代、方式、思维都有所不同。...2020-04-28
- 以下是对C++中的命名规则进行了详细的分析介绍,需要的朋友可以参考下...2020-04-25
- 好的代码书写习惯可以让人赏心悦目,下面这篇文章就给大家分享了PHP符合PSR编程规范的实例代码,有需要的朋友们可以参考借鉴,下面来一起看看吧。...2017-01-08