PHP 代碼規(guī)范

FIG 制定的 PHP 規(guī)范,簡(jiǎn)稱 PSR,是 PHP 開(kāi)發(fā)的事實(shí)標(biāo)準(zhǔn)。FIGFramework Interoperability Group (框架可互用小組) 的縮寫(xiě),由幾位開(kāi)源框架的開(kāi)發(fā)者成立于 2009 年。該組織的目的在于:以最低程度的限制,來(lái)統(tǒng)一各個(gè)項(xiàng)目的編碼規(guī)范,避免各家自行發(fā)展的風(fēng)格阻礙了程序設(shè)計(jì)師開(kāi)發(fā)的困擾。PSRProposing a Standards Recommendation (提出標(biāo)準(zhǔn)建議) 的縮寫(xiě)。

PSR 原來(lái)有五個(gè)規(guī)范,分別是:

  • PSR-0 (Autoloading Standard) 自動(dòng)加載標(biāo)準(zhǔn)。
  • PSR-1 (Basic Coding Standard) 基礎(chǔ)編碼標(biāo)準(zhǔn)。
  • PSR-2 (Coding Style Guide) 編碼風(fēng)格向?qū)А?/li>
  • PSR-3 (Logger Interface) 日志接口。
  • PSR-4 (Improved Autoloading) 自動(dòng)加載的增強(qiáng)版,可以替換掉 PSR-0 了。

今天我們的代碼規(guī)范是基于以上規(guī)范進(jìn)行了整理。

1、PHP 源文件只能使用 <?php<?= 這兩種標(biāo)簽

<?php 標(biāo)簽通常用于純 PHP 的腳本當(dāng)中,而 <?= 通常用于模板當(dāng)中。

2、PHP 源文件必須是不帶 BOMUTF-8 編碼的文件

BOM(Byte Order Mark),字節(jié)順序標(biāo)記,出現(xiàn)在文本文件頭部,Unicode 編碼標(biāo)準(zhǔn)中用于標(biāo)識(shí)文件是采用哪種格式的編碼。

3、PHP 源文件縮進(jìn)采用 4 個(gè)空格

很多編輯器使用 Tab 作為縮進(jìn)。會(huì)造成空格性問(wèn)題。

4、純 PHP 代碼的源文件關(guān)閉標(biāo)簽 ?> 必須省略

PHP 解析器在對(duì)文件進(jìn)行解釋的時(shí)候,會(huì)有性能提升。并且,這能一定程序避免在 ?> 之后有多余的空格導(dǎo)致程序報(bào)錯(cuò)。

5、請(qǐng)嚴(yán)格控制每行 120 個(gè)字符

過(guò)長(zhǎng)的代碼會(huì)導(dǎo)致多種分辨率的顯示器造成兼容問(wèn)題。并且,過(guò)長(zhǎng)的代碼也會(huì)造成難以閱讀理解。如果實(shí)在太長(zhǎng),請(qǐng)把代碼換行。

6、所有的類(lèi)必須設(shè)定一個(gè)命令空間

命令空間給代碼結(jié)構(gòu)有較強(qiáng)的說(shuō)明性,以及杜絕同名類(lèi)的沖突問(wèn)題。同時(shí),也能用到 Composer 的自動(dòng)加載優(yōu)勢(shì)特性。

<?php
namespace core;

?

7、命名空間(namespace)的聲明后面必須有一行空行

空行會(huì)讓代碼看起來(lái)更加清晰容易閱讀。

<?php
namespace core;

use common;

8、所有的導(dǎo)入(use)聲明必須放在命名空間(namespace)聲明的下面

這樣會(huì)讓代碼結(jié)構(gòu)變得清晰容易閱讀。

<?php
namespace core;

use common;

9、一句聲明中,必須只有一個(gè)導(dǎo)入(use)關(guān)鍵字

雖然 PHP 允許一行代碼當(dāng)中允許使用多個(gè) use 關(guān)鍵字導(dǎo)入一個(gè)類(lèi)。但是,這會(huì)使代碼閱讀造成障礙。

錯(cuò)誤:

<?php
namespace core;

use common, library;

正確:

<?php
namespace core;

use common;
use library;

10、在導(dǎo)入(use)聲明代碼塊后面必須有一行空行

空行讓代碼結(jié)構(gòu)變得容易理解。

<?php
namespace core;

use common;
use library;

class Person {
    
}

11、PHP 關(guān)鍵字必須小寫(xiě)

PHP 的關(guān)鍵字,必須小寫(xiě),boolean 值:true,false,null 也必須小寫(xiě)。下面的關(guān)鍵字,也必須小寫(xiě):

'__halt_compiler', 'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor'

12、繼承(extends) 和實(shí)現(xiàn)(implement) 必須和 class name 寫(xiě)在一行,切花括號(hào)要換行寫(xiě)。

<?php
namespace Lib\Databaes;
 
class Mysql extends ParentClass implements \PDO, \DB // 寫(xiě)一行
{ // 換行寫(xiě){
     
}

13、成員屬性訪問(wèn)修飾符必須顯示聲明不能省略

成員屬性有三種訪問(wèn)修飾符:public、protectedprivate。不能使用老式的 var 來(lái)聲音成員屬性。

<?php
namespace Lib\Databaes;
 
class Mysql extends ParentClass implements \PDO, \DB // 寫(xiě)一行
{
    public    $foo  = null;
    private   $name = 'sam';
    protected $age  = '17';
}

14、成員方法訪問(wèn)修飾符必須顯示聲明不能省略

成員方法有三種訪問(wèn)修飾符:public、protected、private。

錯(cuò)誤:

<?php
namespace Lib\Databases;

class MySQL
{
    function fetchOne()
    {
        // ......
    }
}

正確:

<?php
namespace Lib\Databases;

class MySQL
{
    public function fetchOne()
    {
        // ......
    }
}

15、方法的參數(shù)有多個(gè)的時(shí)候,每個(gè)參數(shù)的逗號(hào)后面必須加個(gè)空格

namespace Lib\Databaes;
 
class Mysql extends ParentClass implements \PDO, \DB // 寫(xiě)一行
{
    public getInfo ($name, $age, $gender = 1)
    {
    }
}

16、當(dāng)用到抽象(abstract)和終結(jié)(final)來(lái)做類(lèi)聲明時(shí),它們必須放在可見(jiàn)性聲明(public 還是protected還是private)的前面。而當(dāng)用到靜態(tài)(static)來(lái)做類(lèi)聲明時(shí),則必須放在可見(jiàn)性聲明的后面。

<?php
namespace Vendor\Package;
 
abstract class ClassName
{
    protected static $foo; // static 放后面
 
    abstract protected function zim(); // abstract 放前面
 
    final public static function bar() // final 放前面,static 放最后。
    {
        // 方法主體部分
    }
}

17、控制結(jié)構(gòu)花括號(hào)、換行、空格等規(guī)范

if、else、elseif、switch、for、foreach、case、while、go、try、catch 等關(guān)鍵詞后面必須加空格??梢哉f(shuō),沒(méi)有特殊說(shuō)明的情況下,基本上所有的 PHP 關(guān)鍵詞后面都必須加空格。

流程控制語(yǔ)句起始的花括號(hào)是不需要另起一行。

if ($expr1) { // 左右空格
    // if body
} elseif ($expr2) { // elesif 連著寫(xiě)
    // elseif body
} else {
    // else body;
}

switch ($expr) { // 左右空格
    case 0:
        echo 'First case, with a break'; // 對(duì)齊
        break; // 換行寫(xiě)break,也對(duì)齊。
    case 1:
        echo 'Second case, which falls through';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Third case, return instead of break';
        return;
    default:
        echo 'Default case';
        break;
}

while ($expr) { // 左右空格
    // structure body
}
 
do {
    // structure body; // 左右空格
} while ($expr);

for ($i = 0; $i < 10; $i++) { // 注意幾個(gè)參數(shù)之間的空格
    // for body
}

foreach ($iterable as $key => $value) { // 還是空格問(wèn)題
    // foreach body
}

try {
    // try body
} catch (FirstExceptionType $e) { // 同樣也是注意空格。
    // catch body
} catch (OtherExceptionType $e) {
    // catch body
}

18、類(lèi)名必須與文件名一樣

這個(gè)很容易理解,沒(méi)啥好補(bǔ)充說(shuō)明的。除非框架有特殊的加載規(guī)則。

19、類(lèi)的命名必須遵循 StudlyCaps 大寫(xiě)開(kāi)頭的駝峰命名規(guī)范

StudlyCaps 即單詞首字母大寫(xiě)風(fēng)格。有些人也稱它為大駝峰。

20、方法名稱必須符合 camelCase 式的小寫(xiě)開(kāi)頭駝峰命名規(guī)范

camelCase 即第一個(gè)單詞首字母小寫(xiě)后面的單詞首字母大寫(xiě)的風(fēng)格。

21、類(lèi)中的常量所有字母都必須大寫(xiě),單詞間用下劃線分隔

CONST ORDER_STATUS = 1;

22、變量必須使用小駝峰命名風(fēng)格

$cardNo   = ''; // 卡號(hào)。 
$idCardNo = ''; // 身份證號(hào)。

23、參數(shù)必須使用駝峰命名風(fēng)格

參數(shù)也是變量的一種。故與變量的命名風(fēng)格一致。

24、所有方法的起始花括號(hào)必須另起一行。

雖然以下兩種在實(shí)際開(kāi)發(fā)中都是允許的。但是,為了保持代碼一致。所以,必須強(qiáng)制使用。

錯(cuò)誤:

<?php

class MySQL
{
    public function fetchOne() {
        
    }
}

正確:

<?php

class MySQL
{
    public function fetchOne() 
    {
        
    }
}

25、直接在方法中寫(xiě)數(shù)組參數(shù)時(shí)格式如下

$object->callFunc([
    'userId'   => 1,
    'username' => 'sam',
    'age'      => 20,
    'sex'      => 'male'
]);

26、方法參數(shù)注釋

/**
 * 管理后臺(tái)獲取優(yōu)惠券發(fā)送記錄。
 *
 * @author 7031 2018-02-23
 * @modify 7031 2019-02-25 修復(fù)了 SQL 性能問(wèn)題。
 *
 * @param int    $couponId      優(yōu)惠券ID。
 * @param string $username      用戶名。
 * @param string $mobilephone   用戶手機(jī)號(hào)。
 * @param int    $page          當(dāng)前分頁(yè)頁(yè)碼。
 * @param int    $count         每頁(yè)顯示條數(shù)。
 * @param array  $data          請(qǐng)求參數(shù)。
 *
 * ------------------- eg:start ---------------------
 * $data = [
 *     'username' => '用戶賬號(hào),沒(méi)有時(shí)傳空字符串',
 *     'age'      => '用戶年齡,沒(méi)有時(shí)傳0',
 * ];
 * ------------------- eg:end -----------------------
 *
 * @return array
 */
public static function getBackendSendHistory($couponId = -1, $username, $mobilephone, $page, $count, $data) {

}

可以看出,有以下幾個(gè)注釋特點(diǎn):

1)方法說(shuō)明。

2)創(chuàng)建方法的同事編號(hào)以及時(shí)間。

3)修改方法的同事編號(hào)以及時(shí)間與修改的內(nèi)容。

4)參數(shù)注釋?zhuān)侯?lèi)型、名稱、參數(shù)說(shuō)明。參數(shù)與其他注釋之間要有空行。

5)參數(shù)示例:如果參數(shù)當(dāng)中有復(fù)雜的參數(shù)??梢栽趨?shù)下方給出示例以增強(qiáng)說(shuō)明。

6)返回值。需要給出返回的類(lèi)型。

27、方法的代碼行數(shù)不能超過(guò)一屏

每個(gè)人的顯示器分辨率不一樣。既然不超過(guò)一屏也會(huì)出現(xiàn)別的同事一屏?xí)龅那闆r。所以,即使未超過(guò)一屏,也盡量保證代碼行在 40 行以內(nèi)。如果發(fā)現(xiàn)自己的代碼超過(guò)了 40 行,那么就需要考慮自己的代碼是不是有拆分不合理的地方。特殊情況允許超過(guò) 40 行。但是,整個(gè)方法里面的代碼必須是簡(jiǎn)單的判斷邏輯。不包含復(fù)雜的業(yè)務(wù)判斷邏輯。因?yàn)椋煌臉I(yè)務(wù)判斷最佳實(shí)踐是單獨(dú)封裝一個(gè)方法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容