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自動加載器。