PHP-CS-Fixer braces_position 规则详解:7 个配置项精准控制花括号位置
PHP-CS-Fixer braces_position 规则详解7 个配置项精准控制花括号位置【免费下载链接】PHP-CS-FixerA tool to automatically fix PHP Coding Standards issues项目地址: https://gitcode.com/gh_mirrors/ph/PHP-CS-Fixerbraces_position是 PHP-CS-Fixer 中负责统一花括号{位置的规则允许你按类、匿名类、函数、匿名函数、控制结构五类场景分别指定开括号同行或换行的风格同时控制匿名函数/匿名类是否允许单行书写。读完本文你将掌握该规则的 7 个配置项含义、默认值与future-mode差异看懂全部 8 个官方转换示例并了解其底层 token 处理逻辑与在PSR12、Symfony等规则集中的作用。规则概览规则braces_position的官方定义只有一句话Braces must be placed as configured花括号必须按配置放置。它属于可配置规则CONFIGURABLE对应 Fixer 类为src/Fixer/Basic/BracesPositionFixer.php测试类为tests/Fixer/Basic/BracesPositionFixerTest.php。从源码看该 Fixer 实现了ConfigurableFixerInterface与WhitespacesAwareFixerInterface并混入ConfigurableFixerTrait与IndentationTrait。其isCandidate()判断逻辑非常简单只要 token 流中出现{字符$tokens-isTokenKindFound({)就参与修复因此几乎对所有 PHP 文件生效。配置项详解7 个选项、两类取值规则共开放 7 个配置项。其中 5 个控制开括号位置的选项取值只有两个枚举字符串取值含义same_line开括号与前一行代码放在同一行KR / Allman 混合风格中的同行风格next_line_unless_newline_at_signature_end开括号放在下一行但如果签名末尾右括号)或返回类型之后已经存在换行则保持同行第二个取值是有条件的换行它默认把花括号放到下一行却允许多行签名如每个参数单独一行的写法保留签名末行同行的形态避免出现)单独一行后又跟一个{的怪异排版。该常量在源码中定义为BracesPositionFixer::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END与SAME_LINE见 BracesPositionFixer.php。下表汇总 7 个选项的类型、允许值与默认值均与 官方文档 及源码createConfigurationDefinition()一致配置项类型允许值默认值allow_single_line_anonymous_functionsbooltrue/falsetruefuture-mode 下为falseallow_single_line_empty_anonymous_classesbooltrue/falsetrueanonymous_classes_opening_brace枚举next_line_unless_newline_at_signature_end/same_linesame_lineanonymous_functions_opening_brace枚举同上same_lineclasses_opening_brace枚举同上next_line_unless_newline_at_signature_endcontrol_structures_opening_brace枚举同上same_linefunctions_opening_brace枚举同上next_line_unless_newline_at_signature_end默认值背后的风格分工从默认值可以读出 PHP-CS-Fixer 默认遵循的混合风格类与具名函数开括号换行next_line_unless_newline_at_signature_end——对应 PSR-12 中类声明、函数声明花括号独占一行的要求控制结构、匿名函数、匿名类开括号同行same_line——对应if (...) {、function () {、new class {的常见写法。两个布尔选项则控制单行紧凑写法的放行范围默认允许匿名函数写成function () { return true; }、允许空匿名类写成new class {}但非空的匿名类即使开了allow_single_line_empty_anonymous_classes也会被展开为多行见示例 #7。future-mode 的默认值差异allow_single_line_anonymous_functions的文档标注了Default value (future-mode):false。其实现位于源码的配置定义处-setDefault(Future::getV4OrV3(false, true))。通过src/Future.php中的Future::getV4OrV3()可知在启用未来模式设置环境变量PHP_CS_FIXER_FUTURE_MODE或经runWithEnforcedFutureMode()强制执行时取新值false即未来大版本将默认禁止匿名函数单行书写普通模式下取旧值true。这是 PHP-CS-Fixer 为 v4 平滑迁移提供的预览默认值机制理解它有助于提前评估升级影响。8 个官方示例默认与定制行为对照官方文档提供了 8 个 diff 示例完整覆盖默认配置与 6 种定制组合逐一说明如下。示例 #1默认配置下的整体效果?php -class Foo { class Foo { } -function foo() { function foo() { } -$foo function() -{ $foo function() { }; -if (foo()) -{ if (foo()) { bar(); } -$foo new class -{ $foo new class { };可以看到类、具名函数的开括号被移到下一行匿名函数、控制结构、匿名类的开括号被移到上一行同行。这正是默认值组合的直接体现。示例 #2控制结构开括号换行配置[control_structures_opening_brace next_line_unless_newline_at_signature_end]?php -if (foo()) { if (foo()) { bar(); }适用于希望if/for/while/switch/try等控制结构也采用 Allman 风格花括号独占一行的团队。注意此配置对else、elseif、catch、finally、do、declare、match同样生效——源码中CONTROL_STRUCTURE_TOKENS常量枚举了全部目标 tokenT_DECLARE, T_DO, T_ELSE, T_ELSEIF, T_FINALLY, T_FOR, T_FOREACH, T_IF, T_WHILE, T_TRY, T_CATCH, T_SWITCH以及FCT::T_MATCH见 BracesPositionFixer.php。示例 #3具名函数开括号同行配置[functions_opening_brace same_line]?php -function foo() -{ function foo() { }适合采用 KR 风格书写函数体的团队。需要留意该选项同时作用于命名函数与方法。示例 #4匿名函数开括号换行配置[anonymous_functions_opening_brace next_line_unless_newline_at_signature_end]?php -$foo function () { $foo function () { };示例 #5类开括号同行配置[classes_opening_brace same_line]?php -class Foo -{ class Foo { }示例 #6匿名类开括号换行配置[anonymous_classes_opening_brace next_line_unless_newline_at_signature_end]?php -$foo new class { $foo new class { };示例 #7允许单行空匿名类配置[allow_single_line_empty_anonymous_classes true]?php $foo new class { }; -$bar new class { private $baz; }; $bar new class { private $baz; };关键语义只有空的匿名类花括号间仅含空白或注释才能保持单行一旦体内有实际代码如属性private $baz;即使开启该选项也会被展开为多行。源码中通过$allowSingleLineIfEmpty分支配合遍历括号内 token发现非空白、非注释内容即强制多行的逻辑实现见 BracesPositionFixer.php。示例 #8允许单行匿名函数配置[allow_single_line_anonymous_functions true]?php $foo function () { return true; }; -$bar function () { $result true; - return $result; }; $bar function () { $result true; return $result; };同理单行放行只适用于真正单行的匿名函数如果原代码在花括号内出现换行如示例中$bar的写法规则会把整个函数体展开为标准多行结构。深入源码开括号定位与边界处理applyFix()是整个规则的核心BracesPositionFixer.php它按 token 类型分流处理类/匿名类命中类 token 后向后找{再经TokensAnalyzer::isAnonymousClass()区分匿名类与具名类分别读取anonymous_classes_opening_brace或classes_opening_brace配置。函数/匿名函数命中T_FUNCTION后查找{、;或属性钩子花括号若遇到;如抽象方法或接口方法则跳过用isLambda()区分匿名函数与具名函数。控制结构先定位(...)参数块的结束位置findParenthesisEnd()用BLOCK_TYPE_PARENTHESIS查找配对再取其后第一个有意义 token 判断是否为{。属性钩子PHP 8.4命中T_VARIABLE且后续出现CT::T_PROPERTY_HOOK_BRACE_OPEN时按控制结构规则整理属性钩子的花括号位置并跳过数组默认值等干扰场景。两个值得注意的实现细节签名末端换行检测当配置为next_line_unless_newline_at_signature_end时源码会从开括号向前回溯跳过返回类型相关的 tokenCT::T_TYPE_COLON、T_NULLABLE_TYPE、T_STRING、T_NS_SEPARATOR、T_STATIC、T_CALLABLE、联合/交叉类型等见 BracesPositionFixer.php检查右括号前是否存在换行。测试用例next line with multiline signature与next line with multiline signature and return type系列BracesPositionFixerTest.php验证了多行签名、?int、array、类名、callable等返回类型下的行为。注释安全开括号前后存在注释时规则不会粗暴挪动括号而是借助hasCommentOnSameLine()、isFollowedByNewLine()等辅助方法把括号移动到注释后的合理位置。测试集中open brace preceded by comment and whitespace、open brace surrounded by comment and whitespace等用例BracesPositionFixerTest.php保证了注释场景下不产生破坏性变更。与相邻规则的执行顺序getPriority()返回-2并声明了明确的运行顺序约束必须在该规则之后运行Must run afterControlStructureBracesFixer、MultilinePromotedPropertiesFixer、NoMultipleStatementsPerLineFixer必须在该规则之前运行Must run beforeSingleLineEmptyBodyFixer、StatementIndentationFixer。这保证了控制结构先由control_structure_braces补齐花括号多行提升属性与单行多语句先整理完毕braces_position再统一花括号位置最后由缩进与空体规则收尾。测试覆盖官方兼容性承诺官方文档明确说明The test class defines officially supported behaviour. Each test case is a part of our backward compatibility promise.测试类定义了官方支持的行为每个用例都是向后兼容承诺的一部分。BracesPositionFixerTest.php共 1117 行测试矩阵包括全部控制结构if/else/elseif/else if/for/foreach/while/do-while/switch/try-catch-finally的默认与next line两种形态类、函数、匿名函数、匿名类的默认与定制形态注释行注释//与块注释/* */与开括号的多种组合多行签名、返回类型int、?int、array、\Foo\Bar、callable、staticPHP 8.0 联合类型、8.1 交叉类型、8.2 DNF 类型、8.4 属性钩子property hook包括提升属性中的钩子与带默认值的钩子等版本特性用例以#[RequiresPhp]注解按版本门控。这些用例同时是你在PSR12、Symfony等规则集下启用本规则时的行为基准。所属规则集与内置配置braces_position被以下官方规则集收录完整清单见 官方文档 与src/RuleSet/Sets目录规则集内置配置PER、PER-CS、PER-CS1.0、PER-CS1x0、PER-CS2.0、PER-CS2x0、PER-CS3.0、PER-CS3x0[allow_single_line_anonymous_functions false, allow_single_line_empty_anonymous_classes true]PSR12[allow_single_line_anonymous_functions false, allow_single_line_empty_anonymous_classes true]PSR2[allow_single_line_anonymous_functions false]PhpCsFixer、Symfony[allow_single_line_anonymous_functions true, allow_single_line_empty_anonymous_classes true]对照源码可以印证PSR12Set.php、PSR2Set.php、SymfonySet.phpPSR 系列明确禁止匿名函数单行false而PhpCsFixer/Symfony则保留默认的true。这也解释了为何同一份代码在不同规则集下格式化结果可能不同——选择规则集前应确认其对本规则的覆盖配置。使用建议命令行快速启用php php-cs-fixer fix path/to/file.php --rulesbraces_position在仓库根目录执行或通过.php-cs-fixer.php配置文件在rules数组中按需定制。典型定制场景若团队采用全量 Allman 风格可将control_structures_opening_brace与functions_opening_brace同时设为next_line_unless_newline_at_signature_end若坚持 KR 风格则把classes_opening_brace设为same_line即可。升级兼容关注PHP_CS_FIXER_FUTURE_MODE环境变量下allow_single_line_anonymous_functions将变为false的预告提前在 CI 中验证未来默认值对代码库的影响。从文档到测试再到源码实现braces_position展示了 PHP-CS-Fixer 在花括号位置这一基础排版问题上的完整工程化方案精细的配置粒度、明确的枚举取值、注释与多行签名的边界保护以及严格的测试兼容承诺。掌握它即可在团队中落地统一、可预期的大括号风格。【免费下载链接】PHP-CS-FixerA tool to automatically fix PHP Coding Standards issues项目地址: https://gitcode.com/gh_mirrors/ph/PHP-CS-Fixer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考