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 ?>或<?= ?>標籤中,不可使用其它任何自定義的標籤句法。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自動加載器。

相關文章
相關標籤/搜索