程式碼標準
Symfony 程式碼是由世界各地成千上萬的開發人員貢獻的。為了使每段程式碼看起來和感覺起來都很熟悉,Symfony 定義了一些所有貢獻都必須遵循的程式碼標準。
這些 Symfony 程式碼標準基於 PSR-1、PSR-2、PSR-4 和 PSR-12 標準,因此您可能已經了解其中大部分標準。
使您的程式碼遵循程式碼標準
Symfony 並非手動審查您的程式碼,而是讓確保您貢獻的程式碼符合預期的程式碼語法變得簡單。首先,安裝 PHP CS Fixer tool,然後執行此命令以修正任何問題
1 2
$ cd your-project/
$ php php-cs-fixer.phar fix -v
如果您忘記執行此命令並提出包含任何語法問題的 pull request,我們的自動化工具會警告您並提供解決方案。
Symfony 程式碼標準詳解
如果您想詳細了解 Symfony 程式碼標準,以下是一個簡短範例,其中包含以下描述的大部分功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Acme;
use Other\Qux;
/**
* Coding standards demonstration.
*/
class FooBar
{
public const SOME_CONST = 42;
private string $fooBar;
/**
* @param $dummy some argument description
*/
public function __construct(
string $dummy,
private Qux $qux,
) {
$this->fooBar = $this->transformText($dummy);
}
/**
* @deprecated
*/
public function someDeprecatedMethod(): string
{
trigger_deprecation('symfony/package-name', '5.1', 'The %s() method is deprecated, use Acme\Baz::someMethod() instead.', __METHOD__);
return Baz::someMethod();
}
/**
* Transforms the input given as the first argument.
*
* @param $options an options collection to be used within the transformation
*
* @throws \RuntimeException when an invalid option is provided
*/
private function transformText(bool|string $dummy, array $options = []): ?string
{
$defaultOptions = [
'some_default' => 'values',
'another_default' => 'more values',
];
foreach ($options as $name => $value) {
if (!array_key_exists($name, $defaultOptions)) {
throw new \RuntimeException(sprintf('Unrecognized option "%s"', $name));
}
}
$mergedOptions = array_merge($defaultOptions, $options);
if (true === $dummy) {
return 'something';
}
if (\is_string($dummy)) {
if ('values' === $mergedOptions['some_default']) {
return substr($dummy, 0, 5);
}
return ucwords($dummy);
}
return null;
}
/**
* Performs some basic operations for a given value.
*/
private function performOperations(mixed $value = null, bool $theSwitch = false): void
{
if (!$theSwitch) {
return;
}
$this->qux->doFoo($value);
$this->qux->doBar($value);
}
}
結構
- 在每個逗號分隔符後新增一個空格;
- 在二元運算子 (
==
、&&
、...) 周圍新增一個空格,串聯 (.
) 運算子除外; - 將一元運算子 (
!
、--
、...) 放在受影響變數的旁邊; - 除非您需要型別轉換,否則一律使用完全相同的比較;
- 當檢查變數是否符合運算式時,請使用 尤達條件式,以避免在條件陳述式內發生意外的賦值 (這適用於
==
、!=
、===
和!==
); - 在多行陣列中,即使是最後一個項目之後,也要在每個陣列項目之後新增逗號;
- 在
return
陳述式之前新增一個空行,除非 return 單獨位於陳述式群組內 (例如if
陳述式); - 當函式明確傳回
null
值時,請使用return null;
,當函式傳回void
值時,請使用return;
; - 請勿將
void
傳回型別新增至測試中的方法; - 無論控制結構主體包含的陳述式數量為何,都請使用大括號來表示;
- 每個檔案定義一個類別 - 這不適用於不打算從外部執行個體化,因此不受 PSR-0 和 PSR-4 自動載入標準影響的私有輔助類別;
- 在與類別名稱相同的行上宣告類別繼承和所有實作的介面;
- 在方法之前宣告類別屬性;
- 先宣告公用方法,然後宣告受保護的方法,最後宣告私有方法。此規則的例外情況是類別建構子和 PHPUnit 測試的
setUp()
和tearDown()
方法,這些方法必須永遠是第一個方法,以提高可讀性; - 將所有引數宣告在與方法/函式名稱相同的行上,無論引數數量為何。唯一的例外是使用 建構子屬性提升的建構子方法,其中每個參數都必須在新行上,並加上尾隨逗號;
- 無論建構子有多少引數,在執行個體化類別時都請使用括號;
- 例外和錯誤訊息字串必須使用 sprintf 串聯;
例外和錯誤訊息不得包含反引號,即使在參考技術元素 (例如方法或變數名稱) 時也是如此。必須隨時使用雙引號
1 2
- Expected `foo` option to be one of ... + Expected "foo" option to be one of ...
- 例外和錯誤訊息必須以大寫字母開頭,並以句點
.
結尾; 包含類別名稱的例外、錯誤和棄用訊息必須使用
get_debug_type()
而不是::class
來擷取它1 2
- throw new \Exception(sprintf('Command "%s" failed.', $command::class)); + throw new \Exception(sprintf('Command "%s" failed.', get_debug_type($command)));
- 在傳回或擲回某些內容的
if
和case
條件之後,請勿使用else
、elseif
、break
; - 請勿在
[
偏移存取器周圍和]
偏移存取器之前使用空格; - 為每個不屬於全域命名空間的類別新增
use
陳述式; - 當 PHPDoc 標籤 (例如
@param
或@return
) 包含null
和其他型別時,請務必將null
放在型別清單的末尾。
命名慣例
- 針對 PHP 變數、函式和方法名稱、引數使用 camelCase (例如
$acceptableContentTypes
、hasSession()
);
- 針對組態參數、路由名稱和 Twig 範本變數使用 snake_case
- 變數 (例如
framework.csrf_protection
、http_status_code
);
- 針對常數使用 SCREAMING_SNAKE_CASE (例如
InputArgument::IS_ARRAY
); - 針對列舉案例使用 UpperCamelCase (例如
InputArgumentMode::IsArray
); - 針對所有 PHP 類別、介面、特徵和列舉使用命名空間,並針對其名稱使用 UpperCamelCase (例如
ConsoleLogger
); - 除了 PHPUnit
*TestCase
之外,所有抽象類別都加上Abstract
前綴。請注意,某些早期的 Symfony 類別不遵循此慣例,且基於回溯相容性原因而未重新命名。但是,所有新的抽象類別都必須遵循此命名慣例; - 介面加上
Interface
後綴; - 特徵加上
Trait
後綴; - 請勿針對類別或列舉使用專用的後綴 (例如
Class
或Enum
),但以下列出的情況除外。 - 例外狀況加上
Exception
後綴; - 與服務組態相關的 PHP 屬性加上
As
前綴 (例如#[AsCommand]
、#[AsEventListener]
等); - 與控制器引數相關的 PHP 屬性加上
Map
前綴 (例如#[MapEntity]
、#[MapCurrentUser]
等); - 針對 PHP 檔案命名使用 UpperCamelCase (例如
EnvVarProcessor.php
),針對 Twig 範本和 Web 資產命名使用 snake case (section_layout.html.twig
、index.scss
); - 對於 PHPDoc 和轉型中的型別提示,請使用
bool
(而不是boolean
或Boolean
)、int
(而不是integer
)、float
(而不是double
或real
); - 別忘了查看更詳細的 慣例 文件,以取得更多主觀的命名考量。
服務命名慣例
- 服務名稱必須與其類別的完整類別名稱 (FQCN) 相同 (例如
App\EventSubscriber\UserSubscriber
); - 如果同一個類別有多個服務,請針對主要服務使用 FQCN,並針對其餘服務使用小寫和底線名稱。您可以選擇將它們分成以點分隔的群組 (例如
something.service_name
、fos_user.something.service_name
); - 針對參數名稱使用小寫字母 (除非使用
%env(VARIABLE_NAME)%
語法參考環境變數); - 為公用服務新增類別別名 (例如,將
Symfony\Component\Something\ClassName
別名為something.service_name
)。
文件
- 只有在 PHPDoc 區塊新增與名稱、原生型別宣告或內容不重複的相關資訊 (例如
instanceof
檢查) 時,才為類別、方法和函式新增 PHPDoc 區塊; 僅使用 PHPDoc 參考中定義的註解和型別。為了改善靜態分析的型別,也允許使用下列註解
- 將註解分組在一起,使相同型別的註解緊接在彼此之後,而不同型別的註解則以單一空行分隔;
- 如果方法未傳回任何內容,請省略
@return
註解; - 請勿在類別、方法和函式上使用單行 PHPDoc 區塊,即使它們只包含一個註解 (例如,請勿將
/** {@inheritdoc} */
放在單行中); - 在新增類別或對現有類別進行重大變更時,可以新增或展開包含個人聯絡資訊的
@author
標籤。請注意,可以根據向 核心團隊 提出的要求更新或移除個人聯絡資訊。
許可證
- Symfony 是在 MIT 許可證下發布的,且許可證區塊必須出現在每個 PHP 檔案的頂端,在命名空間之前。
本作品 (包括程式碼範例) 已根據 創用 CC BY-SA 3.0 許可證授權。