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>
//多行显示方式
<?php
echo '多行';
?>
//单行显示方式
<?='单行'?>

</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;
//创建一个类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.php
model file running…

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

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值