编码标准
Symfony 代码由世界各地数千名开发者贡献。为了使每段代码看起来和感觉起来都熟悉,Symfony 定义了一些所有贡献都必须遵循的编码标准。
这些 Symfony 编码标准基于 PSR-1、PSR-2、PSR-4 和 PSR-12 标准,因此您可能已经了解其中大部分。
使你的代码遵循编码标准
Symfony 使确保你贡献的代码与预期的代码语法匹配变得简单,而无需手动审查代码。首先,安装 PHP CS Fixer 工具,然后运行此命令来修复任何问题
1 2
$ cd your-project/
$ php php-cs-fixer.phar fix -v
如果您忘记运行此命令并提交包含任何语法问题的拉取请求,我们的自动化工具会警告您并提供解决方案。
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);
}
}
结构
- 在每个逗号分隔符后添加一个空格;
- 在二元运算符(
==
、&&
、...)周围添加一个空格,连接(.
)运算符除外; - 将一元运算符(
!
、--
、...)放置在受影响变量的旁边; - 始终使用完全比较,除非您需要类型转换;
- 在针对表达式检查变量时使用 Yoda 条件,以避免在条件语句中意外赋值(这适用于
==
、!=
、===
和!==
); - 在多行数组中,即使在最后一个项目之后,也要在每个数组项目后添加逗号;
- 在
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 类、接口、trait 和枚举使用命名空间,并对其名称使用 UpperCamelCase(例如,
ConsoleLogger
); - 所有抽象类都以
Abstract
为前缀,PHPUnit*TestCase
除外。请注意,一些早期的 Symfony 类不遵循此约定,并且出于向后兼容性的原因而未重命名。但是,所有新的抽象类都必须遵循此命名约定; - 接口以
Interface
为后缀; - Trait 以
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
); - 对于 PHPDocs 和类型转换中的类型提示,请使用
bool
(而不是boolean
或Boolean
)、int
(而不是integer
)、float
(而不是double
或real
); - 不要忘记查看更详细的 Conventions 文档,以了解更多主观的命名注意事项。
服务命名约定
- 服务名称必须与其类的完全限定类名 (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 文件的顶部,命名空间之前。
这项工作,包括代码示例,均根据 Creative Commons BY-SA 3.0 许可证获得许可。