PHP 程式碼風格PSR
PSR-1:基本程式寫作標準
1. 總覽
檔案只能使用 <?php 和 <?= 標籤
檔案字元編碼只能用 UTF-8 檔首無 BOM
檔案應該只宣告符號 (class、function、constant)
或是造成副作用(例如產生輸出、修改 .ini 檔之類)兩者擇一
不應該兩個都做Namespace 和 Class 必須遵循"自動載入(PSR-4)"的規範
Class 命名必須用首字母大寫駝峰式(StudlCaps)
Class 常數必須全部用大寫字母命名,多個單字之間用 _ (下底線)連接
Method 命名必須用首字母小寫駝峰式(camelCase)
2. 範例
<?php namespace App\Http\Controllers; class ExampleController extends Controller{ const CONSTANT_VARIABLE = 'test'; public function thisIsExample() { } }
PSR-2:程式碼風格指南
1. 總覽
程式碼必須遵循 PSR-1
程式碼必須用 4 個空格做縮排,而不是 tab
一定不能硬性規定一行字元長度,軟性限制必須在 120 個字以內,一行應該在 80 個字元以內
在宣告 namespace 和 use 的區塊後方一定要空一行
class 的開始左大括弧必須要換下一行,結束右大括弧必須要換到程式碼下一行
method 開始左大括弧必須要換下一行,結束右大括弧必須要換到程式碼下一行
所有的 property 和 method 都必須要宣告可視範圍,abstract 和 final 必須要宣告在可視範圍前,
static 必須宣告在可視範圍之後控制結構關鍵字後面必須要有一個空格,呼叫 method 或 function 時一定不要有空格
控制結構的開始左大括弧必須要在同一行,結束右大括弧必須要換到程式碼下一行
控制結構的開始左小括號後面絕對不要有空格,結束右小括號前面絕對不要有空格
2. 範例
<?php namespace App\Http\Controllers; use App\Services\ExampleService; use App\Services\OtherExampleService as OtherService; class ExampleController extends Controller { const CONSTANT_VARIABLE = 'test'; public function thisIsExample($score) { if ($score >= 90) { //do something } elseif ($score >= 60) { //do something } else { //do something } } final public static function visibilityExample() { //body } }
3. 通用
檔案
所有的 PHP 檔案最後要空一行
只有 php 的檔案一定不加結束 ?> tag
行
不硬性規定每一行長度
軟性限制每一行長度為 120,自動程式碼風格檢查必須要設為警告絕對不能設為錯誤
每行應該不要超過 80 個字元,超過 80 個字元應該要換行,並且每一行都不超過 80 個字元
每一行結局絕對不能有多餘的空格
空行可能會增加可讀性並且指示出相關區塊的程式碼
每一行絕對不能有超過一個語言
縮排
必須要用 4 個空格,絕對不能用 1 個 tab
關鍵字和 true/false/null
PHP 關鍵字一定要用小寫
PHP 的 true, false 和 null 一定要用小寫
Namespace 和 use
Namespace
如果有宣告 namespace,下面一定要加一行空白
use
如果有宣告 use,一定要在 namesapce 之後宣告
一行只宣告一個 use
宣告 use 的區塊下面一定要加一行空白
Classes、Properties、Methods (class 代表 class、interface 和 trait)
Classes
extends 和 implements 關鍵字必須要跟 class 名稱宣告在同一行
開始的左大括弧一定要自己一行,結束的右大括弧一定要換到程式碼下一行
implement 可能會有多行,若是如此,每一個要實作的介面都獨自一行
<?php namespace App\Http\Controllers; use App\Contracts\TestContract; use App\Contracts\SecondContract; use App\Contracts\ThirdContract; class OneImplementClass extends Controller implements TestContract { //繼承和實作關鍵字在同一行 } class MultiImplementClass extends Controller implements TestContract, SecondContract, ThirdContract { //implements 多個介面,一行塞不下所以拆成多行,一行只放一個介面名稱 }
Properties
所有屬性都要宣告可視範圍
絕對不能用 var 這個關鍵字宣告屬性
一行只能宣告一個屬性
protected 或 private 可視範圍的屬性名稱開頭不應該加上 _ 符號
<?php namespace App\Http\Controllers; class TestController { public $foo = null; private $private_foo = null; //private 的屬性名稱不用 _ 開頭 }
Methods
每個 methods 都必須要加可視範圍
protected 或 private 可視範圍的 method 名稱開頭不應該加上 _ 符號
Method 名稱後面絕對不能有空格
Method 開始左大括弧必須往下單獨一行,結束右大括弧必須換行到程式碼下一行,左右大括弧後面都絕對不能有空白
傳入 Method 的多個參數可以拆成多行,若拆成多行時一行只能放一個參數,且第一個參數要換行,開始的左大括弧要跟結束的右小括號同一行,中間用空格隔開
<?php namespace App\Http\Controllers; class TestController { public function testMethod($arg1, $arg2, $arg3 = []) { //左、右大括弧獨自一行,且後方不能有空格 } public function argList( int $arg1, $arg2, array $arg = [] ) { //多個參數可拆成多行,但一行只能放一個參數 //結束的右小括號要跟開始的左大括弧同一行,中間用空格隔開 } private function testPrivateMethod() { //private 可視範圍的 method 前面不用 _ 開頭 } }
abstract, final and static
如果有 abstract 和 final 的話,必須要宣告在可視範圍之前
如果有 static 的話,必須宣告在可視範圍之後
<?php namespace App\Http\Controllers; abstract class TestController { protected static $foo; abstract protected function testAbstract(); final public static function testFinalStatic() { } }
呼叫 Method 和 Function
呼叫 method 或 function 時,在名稱和開始的左小括號中間絕對不能有空格
method 或 function 的開始左小括號後面絕對不能有空格,結束右小括號前面絕對不能有空格
傳入的多個參數,在每個逗點前面絕對不能有空格,在每個逗點後面絕對要有一個空格
多個參數可以拆成多行,若拆成多行時一行只能放一個參數,且第一個參數要換行
<?php namespace App\Http\Controllers; use App\Services\TestService; class TestController { public function testCallMethod() { $test = new TestService(); $test->oneArgument($arg1); //名稱和左小括號中間不能有空格 //每個逗點前面絕對不能有空格,後面絕對要有一個空格 $test->multiArguments($arg1, $arg2, $arg3); //一個參數一行 $test->multiArgsList( $arg1, $arg2, $arg3 ); } }
6. 控制結構
控制結構通用規則
在控制結構關鍵字後面必須要有一個空格
在開始的左小括號後面絕對不能有空格
在結束的右小括號前面絕對不能有空格
在結束的右小括號和開始的左大括弧之間必須要有一個空格
程式碼區塊必須要縮排一次
結束的右大括弧必須要換到程式碼區塊的下一行
每一個控制結構都必須要有結束的右大括弧
if, elseif, else
應該把 else if 替換成 elseif 讓所有控制結構關鍵字看起來像一個字
看以下範例,注意小括號、空格和大括弧,並且 else 和 elseif 和前一個程式區塊的結束大括弧在同一行
<?php namespace App\Http\Controllers; class TestController { public function controlConstruct() { if ($expr1) { // if body } elseif ($expr2) { // elseif body } else { // else body } } }
switch, case
case 語句必須要比 switch 多縮排一次
break 或其他結束關鍵字必須要縮排
如果 case 語句內程式碼區塊不為空且不跳脫,必須加上 // no break 的註解
看以下範例,注意小括號、空格和大括弧
<?php namespace App\Http\Controllers; class TestController { public function controlConstruct() { switch ($expr) { case 0: echo '第一個 case,有 break 跳脫'; break; case 1: echo '第二個 case,沒有用 break 跳脫'; // no break case 2: case 3: case 4: echo '第三個 case, 用 return 代替 break'; return; default: echo '預設的 case'; break; } } }
while, do while
看以下範例,注意小括號、空格和大括弧
<?php namespace App\Http\Controllers; class TestController { public function loopConstruct() { while ($expr) { // while body } do { // do while body } while ($expr); } }
for, foreach
看以下範例,注意小括號、空格和大括弧
<?php namespace App\Http\Controllers; class TestController { public function loopConstruct() { for ($i = 0; $i < 10; $i++) { // for body } foreach ($literable as $key => $value) { // foreach body } } }
try, catch
看以下範例,注意小括號、空格和大括弧
<?php namespace App\Http\Controllers; class TestController { public function exceptionConstruct() { try { // try body } catch (FirstExceptionType $e) { // catch body } catch (OtherExceptionType $e) { // catch body } } }
7. 閉包(Closures)
宣告閉包時,必須在 function 關鍵字後空一格,並且在 use 關鍵字前後都必須要有空格
開始的左大括弧一定要在同一行,結束的右大括弧一定要在程式碼區塊的下一行
在開始的左小括號後面和結束的右小括號前面絕對不能有空格
分隔參數或變數的逗點前一定不能有空格,逗點後一定要有一個空格
有預設值的參數必須要放在最後面
參數和變數可以分割成多行,要縮排一次,第一個參數或變數要換下一行,一行只能有一個參數或變數
如果參數或變數分割成多行,結束的小括號和開始的大括弧要放在同一行,並且用空格隔開
閉包也可以在呼叫 method 或 function 的時候當參數直接傳過去
看以下範例,注意小括號、空格和大括弧
<?php namespace App\Http\Controllers; class TestController { public function closeConstruct() { $var1 = 'test1'; $var2 = 'test2'; $closure_args = function ($arg1, $arg2) { // closure body }; $closure_args_and_vars = function ($arg1, $arg2) use ($var1, $var2) { // closure body }; $multi_args = function ( $arg_line1, $arg_line2, $arg_line3 ) { // closure body }; $long_vars = function () use ( $var1, $var2 ) { // closure body }; $long_args_and_vars = function ( $arg_line1, $arg_line2, $arg_line3 ) use ( $var1, $var2 ) { // closure body }; $foo->bar( $arg1, function ($arg2) use ($var1) { // closure body }, $arg3 ) } }
PSR-4:自動載入
1. 總覽
PSR 明確描述 classes 如何由檔案路徑載入
完全符合規則的命名空間要符合以下格式(class 代表 classes, interfaces, traits)
\<命名空間>(\<子命名空間>)*\<類別名稱>
完整的 class 名稱必須有最高層級的 namespace,像是大家熟知的 "vendor"
完整的 class 名稱可以有一或多個子命名空間
完整的 class 名稱最後必須要有一個 class
完整的 class 名稱內底線不具有任何特殊含意
完整的 class 名稱內大小寫字母可以任意組合
所有的 class 名稱必須大小寫敏感
使用符合規範的 class 名稱載入檔案時...
在完整的 class 名稱裡不包含最前面的分割符號,後續作為命名空間前綴的一個或多個命名空間和子命名空間必須對應至少一個基本目錄
在命名空間前綴之後的子命名空間對應基本目錄內的子目錄,每一個命名空間分隔符號代表目錄分隔符號,子目錄名稱必須完全符合子命名空間大小寫
最後一個的 class 名稱必須符合檔案名稱且大小寫要相符
自動載入絕對不能拋出錯誤,絕對不能提升至任何錯誤層級,並且不應該有回傳值