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 ?>或<?= ?>标签中,不可使用其它任何自定义的标签句法。php
<!doctype html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> //多行显示方式 <?php echo '多行'; ?> //单行显示方式 <?='单行'?> </body> </html>
打印显示:
多行 单行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)读写文件等。web
<?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 { }
关于常量:类的常量全部字符必须大写,词间用下划线分割。composer
//常量命名规范 const PI = 3.14; const BATE_VERSION = '2.1.3';
关于属性:类的属性命名能够遵循(不作强制要求,但选择一种模式后,团队开发时必须统一规范风格):
(1)大写开头的驼峰式($WebName);
(2)小写开头的驼峰式($webName);
(3)下划线分割式($web_name);框架
//属性命名规范 protected $WebName = '西西欢迎大家';
关于方法:方法名称必须严格符合小写开头的驼峰式命名规范。phpstorm
//方法命名规范 public function startApp() { //方法主体 }
举例:编辑器
<?php //命名空间 namespace Psr\Model; //建立一个类Test class 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,让一个单词控制。
<?php if ($flag) { //结构体内部 } elseif ($flag2) { //elseif } else { //else }
15.switch和case
(1)case语句必须相对于switch进行一次缩进;
(2)break语句以及case内部的其它语句都必须相对case进行一次缩进;
(3)非空case直穿语句,主体里必须有相似//no break的注释。
<?php switch ($flag) { case 0: echo '开始阶段'; break; case 1: echo '常规运行'; //不须要break case 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 catch try { //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
<?php require '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.php namespace My\Think\Db; class File { public function run() { echo 'model file running...'; } }
2.执行文件:psr/auto.php
进行自动载入File.php文件
<?php //auto.php require '/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.phpmodel file running...一个完整的类名需具备如下结构:\<命名空间>(\<子命名空间>)*\<类名>(1)完整的类名必需要有一个顶级命名空间;(2)完整的类名能够有一个或多个字命名空间;(3)完整的类名必须有一个最终的类名;(4)完整的类名中任意一部分中的下划线都是没有特殊含义的;(5)完整的类名能够由大小写字母组成;(6)全部类名都必须是大小写敏感的。当根据完整的类名载入相应的文件(1)完整的类名中,去掉最前面的命名空间分隔符,前面连续的一个或多个命名空间和子命名空间,做为「命名空间前缀」,其必须与至少一个「文件基目录」相对应;(2)紧接命名空间前缀后的子命名空间必须与相应的「文件基目录」相匹配,其中的命名空间分隔符将做为目录分隔符。(3)末尾的类名必须与对应的以.php 为后缀的文件同名。(4)自动加载器(autoloader)的实现必定不可抛出异常、必定不可触发任一级别的错误信息以及不该该有返回值。实际中,你根本不须要自行编写符合PSR-4规范的autoload自动加载器。可使用composer来自动生成PSR-4自动加载器。