如題,生物界中任何東西都需要成長,而成長卻也分為兩種,一種是邪惡的成長,一種是健康的成長。
程序員也是一樣的,當我們在成長的時候,必須提前知道規范,從而形成健康的成長,否則養成了大的惡習之後,再後悔卻是如此的痛苦了。
所以,今天就整理了一下PHP的規范,讓大家參考參考。就像大家常說的一句話,“規矩是死的,人是活的。”。是的,但是,在規矩中成長的人都會擁有一堆非常讓人羨慕的好習慣。
所有的縮進使用空格取代Tab制表符。PHP文件采用4個空格的縮進,HTML文件以及HTML文件中嵌入的Javascript代碼采用2個空格的縮進;單獨的 Javascript以及CSS文件采用4個空格的縮進。
所有PHP、HTML文件均保存為No Bom UTF-8的字符編碼。
去掉文件底部 “?>”。
示例:如下例子不符合規范
if (!$valid_ni()){ ... // program code } $repssn_ind = $ssn_data[’index’]->repssn_index; $repssn_ni = $ssn_data[’index’]->ni;
應如下書寫:
if (!valid_ni(){ ... // program code } $repssn_ind = $ssn_data[’index]->repssn_index; $repssn_ni = $ssn_data[index]->ni;
一行程序需小於80字符
較長的語句要分成多行書寫,長表達式要在低優先級操作符處劃分新行,操作符放在新行之首,劃分出的新行要進行適當的縮進,使排版整齊,語句可讀。
循環、判斷等語句中若有較長的表達式或語句,則要進行適應的劃分,長表達式要在低優先級操作符處劃分新行,操作符放在新行之首示例:
$perm_count_msg->len = NO7_TO_STAT_PERM_COUNT_LEN + STAT_SIZE_PER_FRAM * strlen( $len ); $act_task_table[$frame_id * STAT_TASK_CHECK_NUMBER + $index]->occupied = $stat_poi[index]->occupied; $act_task_table[taskno]->duration_true_or_false = sys_get_sccp_statistic_state( $stat_item ); if (($taskno < $max_act_task_number) && (n7stat_stat_item_valid ($stat_item))){ ... // program code } for ($i = 0, $j = 0; ($i < $bufferKeyword[’word_index’]->word_length) && ($j < new_keyword->word_length); $i++, $j++){ ... // program code }
不允許把多個短語句寫在一行中,即一行只寫一條語句。示例:如下例子不符合規范
$rect->length = 0; $rect->width = 0;
應如下書寫:
$rect->length = 0;
$rect->width = 0;
這是因為懶於多敲兩個字符而給代碼清晰帶來問題的又一個情形。
示例:如下例子不符合規范
if ($condition) do_stuff(); if ($condition) do_stuff(); while ($condition) do_stuff(); for ($i = 0; $i < $size; $i++) do_stuff($i);
應如下書寫
if (condition){ do_stuff(); } while ($condition){ do_stuff(); } for ($i = 0; $i < $size; $i++){ do_stuff(); }
示例:如下例子符合規范
switch (){ case ‘1’: ..program break; case ‘2’: ..program break; }
程序塊的分界符(大括號‘{’和‘}’)應各獨占一行並且位於同一列,同時與引用它們的語句左對齊。
而在函數體的開始、類的定義、以及if、for、do、while、switch、case語句中的右大括號應放在行尾, 左大括號應與右大括號所在行的行首處在同一列
示例:如下例子不符合規范
for (...) { ... // program code } if (...) { ... // program code } function example_fun() { ... // program code }
應如下書寫:
for (...){ ... // program code } if (...){ ... // program code } function example_fun(){ ... // program code }
采用這種松散方式編寫代碼的目的是使代碼更加清晰。
由於留空格所產生的清晰性是相對的,所以,在已經非常清晰的語句中沒有必要再留空格,如果語句已足夠清晰則括號內側(即左括號後面和右括號前面)不需要加空格,多重括號間不必加空格。在長語句中,如果需要加的空格非常多,那麼應該保持整體清晰,而在局部不加空格。給操作符留空格時不要連續留兩個以上空格。
示例:如下例子不符合規范
$i=0; if($i<7) ... if ( ($i < 7)&&($j > 8) ) ... for($i=0; $i<$size; $i++) ... $i=($j < $size)?0:1; do_stuff( $i, "foo", $b );
應如下書寫:
$i = 0; if ($i < 7) ... if (($i < 7) && ($j > 8)) ... for ($i = 0; $i < $size; $i++) ... $i = ($j < $size) ? 0 : 1; do_stuff($i, "foo", $b);
當使用字符串連接符時必須在句點(.)兩側加上空格。
示例:如下例子不符合規范
$str = ‘<img src=”’.$thumb_url.’” />’; $str = ‘<img src=”’ .$thumb_url. ‘”/>’;
應如下書寫:
$str = ‘<img src=”’ . $thumb_url . ‘” />’;
誰也不願意看到擠在一堆的無序的代碼。我們在寫代碼的時候總是會利用一些空行來增加代碼可讀性。合理的利用空格來區分代碼段會使代碼的邏輯思路更加明確。我們強行規定的空行有以下兩種情況:
在代碼中我們不允許在行尾有多余的空格。
/** * ShopEx網上商店 文件中文名稱 * 類或者文件的說明,此處可以使用html * * @package * @version $Id$ * @copyright 2003-2008 Shanghai ShopEx Network Tech. Co., Ltd. * @license Commercial * ================================================================= * 版權所有 (C) 2003-2009 上海商派網絡科技有限公司,並保留所有權利。 * 網站地址:http://www.shopex.cn/ * ----------------------------------------------------------------- * 您只能在不用於商業目的的前提下對程序代碼進行修改和使用; * 不允許對程序代碼以任何形式任何目的的再發布。 * ================================================================= */
每個函數之前應當有注釋,告訴一個程序員使用這個函數所需要知道的事情。一個最小化的注釋應包括:每個參數的意義,期望的輸入,函數的輸出。注釋還應當給出在錯誤條件下(還有具體是什麼錯誤條件)這個函數的行為。(注釋應該確保)其他人不必察看這個函數的代碼,就可以自信地在自己的代碼中調用這個函數。
另外,為任何技巧性的,晦澀的或者並非顯而易見的代碼添加注釋,無疑是我們應該做的事情。對文檔尤其重要的是你的代碼所做的任何假設,或者它正確運轉的前提。任何一個開發者應該能夠查看應用程序的任意部分,並且在合理的時間內斷定(代碼的執行中)發生了什麼。
/** * some_func * 函數的含義說明 * <div>這部分可以隨意輸入<b>html</b></div> * 因為這是phpdocument的約定。 * * @param mixed $arg1 參數一的說明 * @param mixed $arg2 參數二的說明 * @access public * @return bool */
廢除的注釋,注釋的代碼要及時刪除
對於所有有物理含義的變量、常量,如果其命名不是充分自注釋的,在聲明時都必須加以注釋,說明其物理含義。變量、常量、宏的注釋應放在其上方相鄰位置或右方。
示例:
// active statistic task number Define(‘MAX_ACT_TASK_NUMBER’,1000) Define(‘MAX_ACT_TASK_NUMBER’,1000); // active statistic task number
注釋應與其描述的代碼相近,對代碼的注釋應放在其上方或右方(對單條語句的注釋)相鄰位置,不可放在下面,如放於上方則需與其上面的代碼用空行隔開。
示例:如下例子不符合規范
例1:
// get replicate sub system index and net indicator $repssn_ind = $ssn_data[$index]->repssn_index; $repssn_ni = $ssn_data[$index]->ni;
例2:
$repssn_ind = $ssn_data[$index]->repssn_index; $repssn_ni = $ssn_data[$index]->ni; // get replicate sub system index and net indicator
應如下書寫
// get replicate sub system index and net indicator $repssn_ind = $ssn_data[$index]->repssn_index; $repssn_ni = $ssn_data[$index]->ni;
數據結構聲明(數組),必須加以注釋。對數據結構的注釋應放在其上方相鄰位置,不可放在下面;對結構中的每個域的注釋放在此域的右方。
示例:按如下形式說明
// sccp interface with sccp user primitive message name $sccp_user_primitive = array( ‘N_UNITDATA_IND’ => 1, // sccp notify sccp user unit data come ‘N_NOTICE_IND => 2, // sccp notify user the No.7 network can not transmission this message N_UNITDATA_REQ => 3 // sccp user's unit data transmission request )
全局變量要有較詳細的注釋,包括對其功能、取值范圍、哪些函數或過程存取它以及存取時注意事項等的說明。
注釋與所描述內容進行同樣的縮排, 可使程序排版整齊,並方便注釋的閱讀與理解。
示例:如下例子不符合規范
function example_fun(){ // code one comments CodeBlock One // code two comments CodeBlock Two } 應改為如下布局: function example_fun(){ //fdgfd CodeBlock One // code two comments CodeBlock Two }
示例:如下例子,顯得代碼過於緊湊。
// code one comments program code one // code two comments program code two
應如下書寫
// code one comments program code one // code two comments program code two
對於switch語句下的case語句,如果因為特殊情況需要處理完一個case後進入下一個case處理,必須在該case語句處理完、下一個case語句前加上明確的注釋。這樣比較清楚程序編寫者的意圖,有效防止無故遺漏break語句。
示例:
switch ($i){ case ‘CMD_INIT’: echo "i equals 0"; break; case ‘CMD_START: echo "i equals 1";// now jump into case CMD_A case ‘CMB_A’: echo "i equals 2"; break; }
代碼中代表結構體的數組變量,要提前聲明。
示例:
function example_fun(){ $student = array( 'name' => '小明', //名稱 'addr' => '詳細地址', //地址 'sex' => '男', //性別 'city' => '上海' //城市 ) }
注釋格式統一,單行注釋必須使用“// …… ”,多行使用一對/*…*/
示例:如下例子不符合規范。
/* if receive_flag is TRUE */ /* if receive_flag is FALSE */ if ($receive_flag)
應如下書寫:
/* if receive_flag is TRUE if receive_flag is FALSE */ if ($receive_flag)
注釋應考慮程序易讀及外觀排版的因素,使用的語言若是中、英兼有的,建議多使用中文,除非能用非常流利准確的英文表達。
代碼中禁止用拼音命名法。
變量名應當全部小寫,並且詞語之間以單個下劃線分隔。
例如: $current_user 是正確的, 但是 $currentuser 和 $currentUser 就不正確。
名稱應當是描述性的,並且簡明。我們自然不希望使用冗長的句子作為變量名,但是多輸入幾個字符總好於疑惑於某個變量到底是干什麼用的。
使用單詞間用單下劃線分隔的小寫名稱,允許動賓詞組為執行某操作的函數命名。如果是OOP方法,可以只有動詞(名詞是對象本身)。允許系表函數命名。
示例:
function print_record($rec_ind) function input_record() function get_current_color() function is_boy()
動詞表:
add / edit / remove begin / end create / destroy first / last get / release get / set increment / decrement put / get lock / unlock open / close min / max old / new start / stop next / previous source / target show / hide send / receive cut / paste up / down
系詞表:
is has
對於私有方法,以_開頭。
允許使用一個單字符變量名的唯一情形是當它作為一個循環計數器的時候。在這種情況下,外層循環的計數器應當始終是 $i。如果有一個循環處於這個循環的內部,它的計數器應當是 $j,進而是 $k,等等。如果循環的計數器是一個已經存在並且名字有意義的變量,本規范並不適用。
例如:
for ($i = 0; $i < $outer_size; $i++){ for ($j = 0; $j < $inner_size; $j++){ foo($i, $j); } }
參數遵循和變量名字相同的約定。我們不希望一堆這樣的函數:do_stuff($a, $b, $c)。在大部分情況下,我們希望僅僅看看函數的聲明,就知道怎樣使用它。
注意運算符的優先級,並用括號明確表達式的操作順序,避免使用默認優先級。防止閱讀程序時產生誤解,防止因默認的優先級與設計思想不符而導致程序出錯。
示例:下列語句中的表達式
$word = ($high << 8) | $low (1) if (($a | $b) && ($a & $c)) (2) if (($a | $b) < ($c & $d)) (3)
如果書寫為
$high << 8 | $low $a | $b && $a & $c $a | $b < $c & $d
由於
$high << 8 | $low = ($high << 8) | $low, $a | $b && $a & $c = ($a | $b) && ($a & $c),
(1)(2)不會出錯,但語句不易理解;
$a | $b < $c & $d = $a | ($b < $c) & $d,
(3)造成了判斷條件出錯。
避免使用不易理解的數字,用有意義的常量來替代。
示例:如下的程序可讀性差。
if ($trunk[$index]->trunk_state == 0){ $trunk[$index]->trunk_state = 1; ... // program code }
應改為如下形式。
define(TRUNK_IDLE, 0) define(TRUNK_BUSY, 1) if ($trunk[$index]->trunk_state == TRUNK_IDLE){ $trunk[$index]->trunk_state = TRUNK_BUSY; ... // program code }
便於程序閱讀和查找。
示例:以下代碼布局不太合理。
$rect->length = 10; $char_poi = $str; $rect->width = 5;
若按如下形式書寫,可能更清晰一些。
$rect->length = 10; $rect->width = 5; // 矩形的長與寬關系較密切,放在一起。 $char_poi = $str;
函數參數的合法性檢查應由函數的調用者負責,接口函數做必要性合法性檢查(不強制)。
總結為:以外為主,以內為輔,內部不強制。
函數的規模限制在100行以內,不包括注釋和空格行。
除調度函數外,多功能集於一身的函數,很可能使函數的理解、測試、維護等變得困難
如果多段代碼重復做同一件事情,那麼在函數的劃分上可能存在問題。若此段代碼各語句之間有實質性關聯並且是完成同一件功能的,那麼可考慮把此段代碼構造成一個新的函數。
三元運算符,在一行代碼裡只允許使用一級
三元運算符只應該用來做簡單的事情。它們只適合拿來做賦值用,根本不是用來做函數調用或者任何復雜的事情的。如果使用不當,它們會影響可讀性,所以不要沉迷於使用它們來減少打字。
示例:不應該使用它們的地方
(($i < $size) && ($j > $size)) ? do_stuff($foo) : do_stuff($bar);
示例:使用它們的合適地方$min = ($i < $j) ? $i : $j;
變量使用前應初始化,error_reporting 將加入 E_NOTICE。意味著,變量未初始化將報錯。這個問題最容易在檢查 HTML 表單傳遞了什麼變量時出現。這些錯誤可以通過使用內嵌的 isset() 或者empty()函數檢查一個變量是否被設置來避免。
示例: 老辦法
if ($forum) ...
新辦法:
if (!empty($forum)) ... if (isset($forum)) …
在 PHP 中有兩種不同的方式引用字符串——使用單引號或使用雙引號。主要區別是:解析器在雙引號括起的字符串中執行變量替換,卻不在單引號括起的字符串中執行。因此,應當始終使用單引號,除非你確實需要對字符串進行變量替換。這樣,我們可以避免讓解析器解析一堆不需要執行替換的字符串的麻煩。同樣,如果你使用字符串變量作為函數調用的一部分,你不需要用引號把那個變量括起來。同樣,那只會給解析器增加不必要的工作。無論如何,要注意幾乎所有雙引號中的轉義序列在單引號中都不會起作用。如果這條規范使你的代碼難以閱讀的話,要小心,並且放心地打破它。
示例:如下例子不符合規范
$str = "This is a really long string with no variables for the parser to find."; do_stuff("$str");
應如下書寫:
$str = 'This is a really long string with no variables for the parser to find.'; do_stuff($str);
當由於可讀性的原因不得不使用雙引號作為引用符時,注意其中所有的變量需用{}包圍:
$str = " This is '{$what}' with no variables for the parser to find."
在 PHP 中,使用一個不用引號括起來的字符串作為一個關聯數組的鍵名是可以運行的。我們不想這樣做——為了避免混亂,這個字符串應當用引號括起來。注意,這只是當我們使用字符串時的情況,不是當我們使用變量時的情況。示例:如下例子不符合規范
$foo = $assoc_array[blah];
應如下書寫:
$foo = $assoc_array['blah'];
簡化自增($i++)和自減($i--)運算符是導致可讀性問題的僅有的簡化運算符。這些運算符不應當被用作表達式的一部分。然而,他們可以獨占一行使用。在表達式中使用它們(帶來的便利)還不夠調試時頭痛的(代價)。
示例:如下例子不符合規范
$array[++$i] = $j; $array[$i++] = $k;
應如下書寫:
$i++; $array[$i] = $j; $array[$i] = $k; $i++;
當條件語句中的條件存在多個,並且有變量值的判斷的時候,需要把變量的判斷語句放在其他的條件語句之前。
示例:如下例子不符合規范
if (function_exists(‘ob_gzhandler’) && $val == 1){ }
應如下書寫:
if ($val == 1 && function_exists(‘ob_gzhandler’)){ }
雖然在 PHP 中else if 和 elseif 的作用基本上是一樣的。但是為了代碼的統一性(也有傳言 else if 會出現不穩定的情況),我們要求將 elseif 之間不保留空格:
if ($bool == 2){ }elseif ($n = 1){ }
無論是函數的參數還是通過URL傳遞的變量,在調用之前均必須對其進行預處理以及設定默認值。
字符串必須進行trim及轉義的處理,並且如果變量的值是在我們預計的范圍之內,需要對變量的非法值做出相應的處理;對於數字型的變量則需要進行intval或者floatval的處理。
在程序中需要使用包含文件的時候我們要求使用require_once或者include_once,不允許使用require或者include。
對於程序必須包含的文件只能采用require_once,而對於某些有條件包含的文件在引用時只能使用include_once。
文件名應當全部小寫,並且詞語之間以單個下劃線分隔。
例如: current_user.php 是正確的, 但是 currentuser.php 和 currentUser.php 就不正確。
名稱應當是描述性的,並且簡明。我們自然不希望使用冗長的句子作為文件名,但是多輸入幾個字符總好於疑惑於某個文件到底是干什麼用的。
既然我們都在使用不同的編輯器設置,不要嘗試去做諸如在 SQL 代碼中實現列對齊此類的麻煩事。要做的是,不管用何種方法,把語句斷行到它們單獨的行上去。這裡有一個 SQL 代碼看上去應該是什麼樣子的示例。注意在哪裡斷行,大寫,和括號的用法。
例如:
SELECT field1 AS something, field2, field3 FROM `table` a, `table` b WHERE (this = that) AND (this2 = that2)
SQL語句中的表名與字段名避免使用保留字;同時所有字段值的變量名,如果是數值型,需要強制類型轉換。intval,floatval…
在已知需要查詢的字段的前提下,不允許使用如下的代碼:
SELECT * FROM `mytable`
取而代之的寫法是將每一個字段名寫上去,請不要偷懶。
SELECT col1, col2, col3 FROM `mytable`
在需要獲得已知記錄數量情況下,請使用 LIMIT offset, count 的方式,盡量不要使用無 LIMIT 的 SELECT 語句。
在需要或者滿足條件的記錄數量的情況下,請使用 SELECT count([*|col1]) FROM 的方式,盡量不要使用 SELECT col1 FROM 的方式。
需要進行邏輯運算的時候,盡量不要使用不等於,可以使用大於或者小於的方式。
SQL INSERT 語句可以寫成兩種不同方式。或者你明確指明要插入的列,或者你已經知道數據中各列的順序,不用詳細指定它們。我們希望使用前一種方法,也就是詳細說明插入哪些列。這意味著應用程序代碼不會依賴於數據庫中字段的順序,也不會因為我們增加另外的字段而崩潰(當然,除非它們被指定為 NOT NULL)。
例如:
# 這不是我們想要的 INSERT INTO `mytable` VALUES ('something', 1, 'else') # 這是正確的。 INSERT INTO `mytable` (column1, column2, column3) VALUES ('something', 1, 'else')
界定符為 <{ }>
為了避免dreamweaver將Smarty語句中的雙引號改寫為",我們要求在Smarty的花括號中不允許使用雙引號,而是使用單引號。
錯誤的寫法:
<{if $user_name eq ""}>匿名用戶<{/if}> <{insert name=”query_info”}>
正確的寫法:
<{if $user_name eq ''}>匿名用戶<{/if}> <{insert name=’query_info’}>
當需要在模板中有條件的設置HTML元素屬性值的時候,我們要求所有語句均包含在雙引號之內。錯誤的代碼:
<div class= <{if $promote_price>0}>"promote_goods" <{else}>”normal_goods”<{/if}> ><{$goods.goods_name}></div>
正確的寫法:
<div class="<{if $promote_price gt 0}>promote_goods <{else}>nomarl_goods<{/if}>"><{$goods.goods_name}></div>
在smarty中可以用eq、neq、gt、lt等來分別表示==、!=、>、<。那我們到底該使用哪種呢?
當Smarty語句出現在HTML標簽內時不允許使用==、!=這類修飾符,如果使用了這類修飾符有可能導致該符號或者其他的HTML相關符號被Dreamweaver自動轉義。
總之,盡量使用eq、gt等這類條件修飾符,避免直接使用==、>。