PHP編碼軌範2
最後更新:2016-06-13
來源:互聯網
上載者:User
PHP編碼規範2
1 介紹
為了更好的提高開發的工作效率,保證開發的有效性和合理性,並最大程度的提高代碼的可讀性和可重複利用性,制訂此規範。本規範包含了PHP開發時程式編碼中代碼縮排規則、控制結構、函數調用、函數定義、注釋、包含代碼、PHP標記、檔案頭的註解區塊、CVS標記、URL範例、常量命名等方面的規則。
1.1 標準化的重要
標準化問題的確在某些方面上讓每個人頭痛,讓人人都覺得大家處於同樣的境地。但是這往往是因為對標準化的誤解。標準化不是束縛人,他是為了在大型開發過程中,能夠提供項目整體的品質與開發進度。也許有人會說,恩,我不喜歡束縛,這麼做會約束我的創造力。如果說你的創造力僅僅在命名,格式(而這恰恰是規範的主要內容)這樣的表面層次,那麼把你的創造力扔掉吧,沒人喜歡這樣的創造力。
1.2 優點
當一個項目嘗試著遵守公用的標準時,會有以下好處:
· 程式員可以瞭解任何代碼,弄清程式的狀況
· 新人可以很快的適應環境
· 防止新接觸php的人出於節省時間的需要,自創一套風格並養成終生的習慣
· 防止新接觸php的人一次次的犯同樣的錯誤
· 在一致的環境下,人們可以減少犯錯的機會
· 程式員們有了一致的敵人
1.3 改進
規範並不是一成不變的,如果你覺得規範缺少東西或者有些不合適的地方,提出來,也許專案管理者會考慮加入,記住,任何項目都取決於團隊合作的努力。
1.4 實施
一般情況下,規範的實施是由技術負責人或者專案經理執行和監督的。但是最好的方法還是在Team Dev中達成共識,變成一種文化的存在。
2 命名規則
命名是程式規劃的核心。名字就是事物在它所處的生態環境中一個長久而深遠的結果。總的來說,只有瞭解系統的程式員才能為系統取出最合適的名字。如果所有的命名都與其自然相適合,則關係清晰,含義可以推導得出,一般人的推想也能在意料之中。
如果你發覺你的命名只有少量能和其對應事物相匹配的話, 最好還是重新好好再看看你的設計。
2.1 檔案命名
檔案名稱採用C GNU的慣例,所有的字母使用小寫字母,使用`_`分割單詞。
例如:
news_list.php
檔案命名上有些幾乎是約定俗成的單詞,比如admin首碼表示是後台管理的檔案名稱,inc.php尾碼則表示包含檔案或者類庫檔案,class.php尾碼表示類庫檔案等等。config.php表示設定檔等。
例如:
admin_user.php
data.inc.php
user.class.php
2.2 類命名
· 使用大寫字母作為詞的分隔,其他的字母均使用小寫
· 名字的首字母使用大寫
· 不要使用底線(`_`)
例如
class NameOneTwo
class Name
注意:
· 在為類(class )命名前首先要知道它是什麼。如果看到類名,你還是想不起這個類是什麼的話,那麼你的設計就還做的不夠好。
· 超過三個片語成的混合名是容易造成系統各個實體間的混淆,再看看你的設計,嘗試使用(CRC Session card)看看該命名所對應的實體是否有著那麼多的功用。
· 對於衍生類別的命名應該避免帶其父類名產生關係,一個類的名字只與它自身有關,和它的父類叫什麼無關。
· 有些尾碼名是幾乎是約定俗成的,例如:如果你的系統使用了代理(agent ),那麼就把某個組件命名為“下載代理”(DownloadAgent)用以真正的傳送資訊。
當然,這些約定俗成的詞彙不會自動出現,需要小組人員的不斷總結。
2.2.1 縮寫詞不要全部使用大寫字母
· 無論如何,當遇到以下情況,你可以用首字母大寫其餘字母小寫來代替全部使用大寫字母的方法來表示縮寫詞。
使用: GetHtmlStatistic.
不使用: GetHTMLStatistic.
理由
· 當命名含有縮減詞時,人們似乎有著非常不同的直覺。統一規定是最好,這樣一來,命名的含義就完全可以預知了。
舉個NetworkABCKey的例子,注意C是應該是ABC裡面的C還是key裡面的C,這個是很令人費解的。有些人不在意這些,其他人卻很討厭這樣。所以你會在不同的代碼裡看到不同的規則,使得你不知道怎麼去叫它。
例如
class FluidOz // 不要寫成 FluidOZ
class GetHtmlStatistic // 不要寫成 GetHTMLStatistic
2.3 類庫命名
· 目前命名空間正在越來越廣泛的被採用,以避免不同廠商和團體類庫間的類名衝突。
· 當尚未採用命名空間的時候,為了避免類名衝突,一般的做法是在類名前加上獨特的首碼,兩個字元就可以了,當然多用一些會更好。
例如
John Johnson的資料結構類庫可以用Jj做為首碼,如下:
class JjLinkList
{
}
另一種折中方式是建立包含類庫目錄(事實上Java也是這麼做的),以不通的目錄代表不同的命名空間。
例如
Microsoft的資料庫相關類庫可以在:
/classes/com/Microsoft/ Database/DbConn.php
Apache的資料庫相關類庫可在:
/classes/org/apache/Database/DbConn.php
2.4 類屬性命名
· 類屬性採用C GNU的慣例,所有的字母使用小寫字母,使用`_`分割單詞。
例如
class NameOneTwo
{
function var_abc() {};
function error_number() {};
var $var;
var $error_number;
var $name;
}
2.5 方法命名
·函數名字採用C GNU的慣例,所有的字母使用小寫字母,使用`_`分割單詞。
例如
class NameOneTwo
{
function do_it() {};
function handle_error() {};
}
· 通常每個方法都是執行一個動作的,所以對它們的命名應該清楚的說明它們是做什麼的:用check_for_errors()代替error_check(),用dump_data_to_file()代替data_file()。這麼做也可以使功能和資料成為更可區分的物體。
· 有時尾碼名是有用的:
o Max - 含義為某實體所能賦予的最大值。
o Cnt - 一個運行中的計數變數的當前值。
o Key - 索引值。
例如:retry_max 表示最多重試次數,retry_cnt 表示當前重試次數。
· 有時首碼名是有用的:
o Is - 含義為問一個關於某樣事物的問題。無論何時,當人們看到Is就會知道這是一個問題。
o Get - 含義為取得一個數值。
o Set - 含義為設定一個數值
例如:is_hit_retry_limit。
2.6 方法中參數命名
·函數名字採用C GNU的慣例,所有的字母使用小寫字母,使用`_`分割單詞。
例如
class NameOneTwo
{
function start_your_engines(
&$some_engine,
&$another_engine);
}
2.7 變數命名
· 所有字母都使用小寫
· 使用`_`作為每個詞的分界。
理由
· 通過這一途徑,代碼中變數的範圍是清晰的。
· 所有的變數在代碼中都看起來不同,容易辨認。
例如
function handle_error($errorNumber)
{
$error = OsErr($errorNumber);
$time_of_error = $error->get_time_of_error();
$error_processor = $error->get_error_processor();
}
2.8全域常量
· 全域常量用`_`分隔每個單詞,並且全部單詞大寫。
理由
這是命名全域常量的傳統。你要注意不要與其它的定義相衝突。
例如
define("A_GLOBAL_CONSTANT", "Hello world!");
2.9 靜態變數
· 靜態變數應該帶首碼‘s’。
理由
· 知道一個變數的範圍是非常重要的。
例如
function test()
{
static $msStatus = 0;
}
2.10 函數命名
· 函數名字採用C GNU的慣例,所有的字母使用小寫字母,使用`_`分割單詞。
理由
· 這樣可以更易於區分相關聯的類名。
例如
function some_bloody_function()
{
}
2.11 錯誤返回檢測規則
· 檢查所有的系統調用的錯誤資訊,除非你要忽略錯誤。
· 為每條系統錯誤訊息定義好系統錯誤文本以便include。
3 書寫規則
3.1 大括弧{}
在三種主要的大括弧放置規則中,有兩種是可以接受的,如下的第一種是最好的:
· 將大括弧放置在關鍵詞下方的同列處:
if ($condition)
{
... ...
}
while ($condition)
{
... ...
}
· 傳統的UNIX的括弧規則是,首括弧與關鍵詞同行,尾括弧與關鍵字同列:
if ($condition) {
... ...
}
while ($condition) {
... ...
}
理由:
引起劇烈爭論的非原則的問題可通過折衷的辦法解決,兩種方法任意一種都是可以接受的,然而對於大多數人來說更喜歡第一種。原因就是心理研究學習範疇的東西了。
對於更喜歡第一種還有著更多的原因。如果您使用的字元編輯器支援括弧匹配功能的話(例如vi),最重要的就是有一個好的樣式。為什嗎?我們說當你有一大塊的程式而且想知道這一大塊程式是在哪兒結束的話。你先移到開始的括弧,按下按鈕編輯器就會找到與之對應的結束括弧,例如:
if ($very_long_condition && $second_very_long_condition)
{
...
}
else if (...)
{
...
}
從一個程式塊移動到另一個程式塊只需要用游標和你的括弧匹配鍵就可以了,不需找匹配的括弧。
3.2 縮排:定位字元vs空格
在書寫代碼的時候,必須注意代碼的縮排規則,我們規定:使用4個空格作為縮排,而不使用tab縮排(對於ultraedit,可以進行預先設定)。
·對於最大縮排層數,並沒有一個固定的規矩,假如縮排層數大於四或者五層的時候,你可以考慮著將代碼因數分解(factoring out code)。
理由
· 許多編程者支援定位字元。 但定位字元標準在各種編程工具下、各種平台下所代表的空格數或者意義是不同的。這樣會使在一個平台下格式良好的代碼在另一個平台下不堪入目。對於php的開發來說,通常情況下是在win平台下開發,linux下部署,尤其需要注意這個問題。
· 雖然此處沒有限定最大的縮排層數,但是通常建議不要超過四層、五層。
例如:
function func()
{
if (something bad)
{
if (another thing bad)
{
while (more input)
{
}
}
}
}
3.3 小括弧、關鍵詞和函數
· 不要把小括弧和關鍵詞緊貼在一起,要用空格隔開它們。
· 小括弧和函數名間沒有空格;如$test = date("ymdhis");
· 除非必要,不要在Return返回語句中使用小括弧。
理由
· 關鍵字不是函數。如果小括弧緊貼著函數名和關鍵字,二者很容易被看成是一體的。
例如
if (condition)
{
}
while (condition)
{
}
strcmp($s, $s1);
return 1;
3.4 類的建構函式
別在建構函式中做實際的工作, 建構函式應該包含變數的初始化和(或)不會發生失敗的操作。
理由
· 構造不能返回錯誤 。
例如
class Device
{
function device() { /* initialize and other stuff */ }
function open() { return FAIL; }
};
$dev = new Device;
if (FAIL == $dev->open()) exit(1);
3.5 =符號書寫
在程式中=符號的書寫遵循以下規則:
(1)在=符號的兩側,均需留出一個空格;如$a = $b 、if ($a = = $b)等;
(2)在一個申明塊,或者實現同樣功能的一個塊中,要求=號盡量上下對齊,左邊可以為了保持對齊使用多個空格,而右邊要求空一個空格;如下例:
$testa = $aaa;
$testaa = $bbb;
3.6 控制結構
3.6.1 if then else 格式
不同的花括弧樣式會產生些微不同的樣觀。一個通用方式是:
if (條件1) // 注釋
{
}
else if (條件2) // 注釋
{
}
else // 注釋
{
}
如果你有用到else if 語句的話,通常最好有一個else塊以用於處理未處理到的其他情況。可以的話放一個記錄資訊注釋在else處,即使在else沒有任何的動作。
·總是將恒量放在等號/不等號的左邊,例如:
if ( 6 == $errorNum ) ...
一個原因是假如你在等式中漏了一個等號,語法檢查器會為你報錯。第二個原因是你能立刻找到數值而不是在你的運算式的末端找到它。需要一點時間來習慣這個格式,但是它確實很有用。
3.6.2 switch 格式
· 當一個case塊處理後,直接轉到下一個case塊處理,在這個case塊的最後應該加上注釋。
· default case總應該存在,它應該不被到達,然而如果到達了就會觸發一個錯誤。
· 如果你要創立一個變數,那就把所有的代碼放在塊中。
例如
switch (...)
{
case 1:
...
// FALL THROUGH
case 2:
{
$v = get_week_number();
...
}
break;
default:
}
3.6.3 continue 和 break
continue 和 break 其實是變相的隱形 goto方法。
continue 和 break 像 goto 一樣,它們在代碼中是有魔力的,所以要節儉(儘可能少)的使用它們。使用了這一簡單的魔法,由於一些未公開的原因,讀者將會被定向到只有上帝才知道的地方去。
continue有兩個主要的問題:
· 它可以繞過測試條件。
· 它可以繞過等/不等運算式。
看看下面的例子,考慮一下問題都在哪兒發生:
while (TRUE)
{
...
// A lot of code
...
if (/* some condition */) {
continue;
}
...
// A lot of code
...
if ( $i++ > STOP_VALUE) break;
}
注意:"A lot of code"是必須的,這是為了讓程式員們不能那麼容易的找出錯誤。
通過以上的例子,我們可以得出更進一步的規則:continue 和 break 混合使用是引起災難的正確方法。
3.6.4 ?:
?:本身沒什麼問題,問題在於人們往往試著在 ? 和 : 之間塞滿了許多的代碼。以下的是一些清晰的串連規則:
· 把條件放在括弧內以使它和其他的代碼相分離。
· 如果可能的話,動作可以用簡單的函數。
· 把所做的動作,“?”,“:”放在不同的行,除非他們可以清楚的放在同一行。
例如
(condition) ? funct1() : func2();
or
(condition)
? long statement
: another long statement;
3.7 聲明塊的定位
· 聲明代碼塊需要對齊。
理由
· 清晰。
· 變數初始化的類似代碼塊應該列表。
· &應靠近類型,而不是變數名。
例如
var $mDate
var& $mrDate
var& $mrName
var $mName
$mDate = 0;
$mrDate = NULL;
$mrName = 0;
$mName = NULL;
3.8 每行語句應盡量短
除非這些語句有很密切的聯絡,否則每行唯寫一個語句。
在代碼書寫中,遵循以下原則:
(1)盡量保證程式語句一行就是一句,而不要讓一行語句太長產生折行;
(2)盡量不要使一行的代碼太長,一般控制在80個字元以內;
(3)如果一行代碼太長,請使用類似 .= 的方式斷行書寫;
(4 對於執行資料庫的sql語句操作,盡量不要在函數內寫sql語句,而先用變數定義sql語句,然後在執行操作的函數中調用定義的變數;
例如:
$sql = "SELECT username,password,address,age,postcode FROM test_t ";
$sql .= " WHERE username='aaa'";
$res = mysql_query($sql);
3.9 短方法
方法代碼要限制在一頁內。
3.10記錄所有的空語句
總是記錄下for或者是while的空塊語句,以便清楚的知道該段代碼是漏掉了,還是故意不寫的。
while ($dest++ = $src++)
; // VOID
3.11 不要採用預設方法測試非零值
不要採用預設值測試非零值,也就是使用:
if (FAIL != f())
比下面的方法好:
if (f())
即使 FAIL 可以含有 0 值 ,即PHP認為是false。但當某人決定用-1代替0作為失敗傳回值時,一個顯式的測試就可以協助你了。即使是比較值不會變化也應該使用顯式的比較;
例如:
if (!($bufsize % strlen($str)))
應該寫成:
if (($bufsize % strlen($str)) == 0)
以表示測試的數值(不是布爾)型。一個經常出問題的地方就是使用strcmp來測試一個字元等式,結果永遠也不會等於預設值。
非零測試採用基於預設值的做法,那麼其他函數或運算式就會受到以下的限制:
· 只能返回0表示失敗,不能為/有其他的值。
· 命名以便讓一個真(true)的傳回值是絕對顯然的,調用函數IsValid()而不是Checkvalid()。
3.12 布爾邏輯類型
遵循以下規則:
(1) 不能使用0/1代替true/false,在PHP中,這是不相等的;
(2) 不要使用非零的運算式、變數或者方法直接進行true/false判斷,而必須使用嚴格的完整true/false判斷;
如:不使用if ($a) 或者if (checka()) 而使用if (FALSE != $a)或者 if (FALSE != check())
大部分函數在FALSE的時候返回0,但是並非0值就代表TRUE,因而不要用1(TRUE,YES,諸如此類)等式檢測一個布爾值,應該用0(FALSE,NO,諸如此類)的不等式來代替:
if (TRUE == func()) { ...
應該寫成:
if (FALSE != func()) { ...
3.13 通常避免嵌入式的賦值
有時候會看到嵌入式賦值的語句,這樣的結構可讀性強並不強
while ($a != ($c = getchar()))
{
process the character
}
++和--操作符類似於指派陳述式。因此,出於許多的目的,在使用函數的時候會產生副作用。使用嵌入式賦值提高運行時效能是可能的。無論怎樣,程式員在使用嵌入式指派陳述式時需要考慮在增長的速度和減少的可維護性兩者間加以權衡。例如:
a = b + c;
d = a + r;
不要寫成:
d = (a = b + c) + r;
雖然後者可以節省一個周期。但在長遠來看,隨著程式的維護費用漸漸增長,程式的編寫者對代碼漸漸遺忘,就會減少在成熟期的最佳化所得。
4 注釋
PHP中有兩種注釋方法,一種是使用//開始,另外一種是使用/**/。 //一般用來比較簡短的注釋。/**/則用在需要大量注釋的代碼中。
注釋要盡量清晰,扼要,同時要使得你的注釋能被機器解析後,能以固定的格式放到手冊中去。注釋的種類主要包括:類的注釋,屬性注釋、方法注釋、變數注釋以及關鍵演算法、重要代碼實現等。所有的這些部分編織在一起,使得人們在以後的時間裡能夠準確的知道你幹了什麼,為什麼這麼做。
在注釋時,有一些預定義的關鍵字用來表示方法的目的,作者等,這樣那就不需要再起另外一套關鍵字或者說不懂中文而採用漢語拼音。
注釋是增加程式可讀性、可維護性的一種方法,而不是唯一方法。可讀性和可維護性主要還是在代碼命名,項目組織處提高。
4.1 預定義關鍵字
關鍵字 含義
Purpose 表示類、屬性、方法要做些什麼或者什麼含義。
Package Name 類名
Author 作者
Modifications 修改記錄(編號規則為“No”+日期+“-”+序號)
Ref 參考
Method Name 方法名
Parameter 參數名(包括類型)
Return 傳回值(包括類型)
Attribute/Variable Name 屬性/變數名
Type 屬性/變數類型
4.2 檔案頭注釋
每個檔案頭部必須有統一的註解區塊,規則如下:
a. 必須包含本檔案的描述;
b. 必須包含作者;
c. 必須包含書寫日期;
d. 必須包含版本資訊;
e. 必須包含項目名稱;
f. 必須包含檔案的名稱;
g. 重要的使用說明,如類的調用方法、注意事項等;
參考例子如下:
//
// +---------------------+
// | PHP version 4.0 |
// +---------------------+
// | Copyright (c) 1997-2001 The PHP Group |
// +---------------------+
// | This source file is subject to of the PHP license, |
// | that is bundled with this packafile LICENSE, and is |
// | available at through the world-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the and are unable to |
// | obtain it through the world-wide-web,end a note to |
// | [email protected] so we can mail you a immediately. |
// +---------------------+
// | Authors: Stig Bakken <[email protected]> |
// | Tomas V.V.Cox <[email protected]> |
// | |
// +---------------------+
//
// $Id: Common.php,v 1.8.2.3 2001/11/13 01:26:48 ssb Exp $
4.3 類的注釋
每個類注釋需要包含以下項目:
a. 必須包含類的描述;
b. 必須包含作者;
c. 必須包含書寫日期;
d. 必須包含版本資訊;
e. 名稱空間(可選);
f. 參考(可選);
參考例子如下:
/**
* @ Purpose:
* 訪問資料庫的類,以ODBC作為通用提供者
* @Package Name: Database
* @Author: Forrest Gump [email protected]
* @Modifications:
* No20020523-100:
* odbc_fetch_into()參數位置第二和第三個位置調換
* John Johnson [email protected]
* @ref: (參照)
*/
class Database
{
……
}
4.4 方法注釋
每個類注釋需要包含以下項目:
a. 必須方法描述;
b. 必須包含方法名稱;
c. 必須包含收入參數及類型;
d. 必須包含輸出參數及類型;
參考例子如下:
/**
* @Purpose:
* 執行一次查詢
* @Method Name: query()
* @Parameter: string $queryStr SQL查詢字串
* @Return: mixed 查詢傳回值(結果集對象)
*/
function($queryStr){……}
4.5 屬性注釋
屬性注釋需要包含以下項目:
a.屬性簡短描述(必須);
參考例子如下:
//使用者名稱
var mDbUserName;
4.6 變數注釋
變數注釋需要包含以下項目:
a.變數簡短描述(可選);
變數在程式中出現次數是最多的,而且變數從其名字中應該能清楚看到其意義。對臨時性變數、範圍較窄的變數可以省略注釋,否則程式中將因為注釋而變得非常臃腫。
參考例子如下:
//使用者名稱
$user_name;
4.7 代碼塊注釋
代碼塊注釋僅在必要時才使用,例如程式關鍵演算法等等。注釋方法同變數和屬性。
參考例子:
func f()
{
… …
//此處使用的是冒泡排序
… …
}
5 項目組織
此節主要在項目層次對涉及的文檔,源碼,說明等做出一些建議性方法。根據項目屬性的不同,下面的部分可進行一些增刪處理。
5.1 項目結構
·設計文檔
主要是軟體設計類圖,包圖,資料庫結構,關鍵演算法參考等
·項目說明
主要包含軟體安裝,使用說明,初始帳號,注意事項等,以指導人們顯示資源:
·源碼
指能通過編譯的或者運行正常的源碼
·工程管理
包括需求文檔,專案管理,Bug修複等。
除了上述文檔外,可能含有其他形形色色的文檔,到時按照項目定義的類型進行歸檔即可。
5.2 源碼結構
此處主要介紹在開發企業網站或者小型網站中,常用的一些目錄命名。當然如果你要開發的項目類似於百度或者新浪,你可能不會需要,因為那時會有專業的人員或者規範進行約束,方方面面都已經涉及。通常情況下,這些還是對你有協助的。
一個完整獨立的PHP項目目錄結構如下:
/ 項目根目錄
/manage(admin) 後台管理檔案存放目錄
/css css檔案存放目錄
/images 所有圖片檔案存放路徑(在裡面根據目錄結構設立子目錄)
/scripts 用戶端js指令碼存放目錄
/tpl 網站模版檔案存放目錄
/uploads 上傳檔案目錄
/inc(include) 全域函數包含檔案目錄
/cache 緩衝目錄
/install 安裝程式目錄
以上目錄結構是通常的目錄結構,根據具體應用的具體情況,可以考慮不用完全遵循,但是盡量做到正常化。
5.3 第三方開發包
對於在開發中引入的第三方開發包,如果可能,盡量將其放入單獨目錄進行管理,同時在項目文檔中放入開發包的相關文檔:協助文檔,原理介紹,項目地址等。