FIG 制定的
PHP規(guī)范,簡(jiǎn)稱PSR,是PHP開(kāi)發(fā)的事實(shí)標(biāo)準(zhǔn)。FIG是Framework 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ā)的困擾。PSR是Proposing 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 源文件必須是不帶 BOM 的 UTF-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、protected、private。不能使用老式的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è)方法。