PHP-CS-Fixer 的 align_multiline_comment 规则:多行注释星号对齐与 comment_type 配置实战
2026/9/23 23:44:27 网站建设 项目流程
  • 开发工具
  • 代码质量
  • 静态分析
  • Lint
  • 格式化

【免费下载链接】PHP-CS-Fixer

A tool to automatically fix PHP Coding Standards issues

项目地址:https://gitcode.com/gh_mirrors/ph/PHP-CS-Fixer
点击查看免费下载

导读

本文围绕 PHP-CS-Fixer 仓库中的align_multiline_comment规则展开,它负责强制多行 DocBlock 注释(以及可选的普通多行注释)每一行都必须以星号*开头,并与首行星号对齐,从而符合 PSR-5 关于 DocComment 的书写规范。读完本文,你将掌握该规则的三种comment_type配置(phpdocs_only/phpdocs_like/all_multiline)的区别与适用场景、其底层的 Token 级修复原理、与其他 phpdoc 规则的执行优先级关系,以及如何在命令行和配置文件中启用它。

规则概览:它到底修复什么

按照官方文档(见 doc/rules/phpdoc/align_multiline_comment.rst)的表述,该规则的核心职责是:

Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one.

即:多行 DocComment 的每一行都必须有星号,且必须与第一行对齐。这一要求源自 PSR-5(已被放弃但影响深远的 PHPDoc 规范草案)对 DocComment 结构的规定。

实际开发中,代码格式化工具、IDE 重构、手工复制粘贴常常产生两类"脏"注释:

  • 某行缺少前导星号(如with a line not prefixed with asterisk);
  • 星号存在但缩进错乱(星号不在同一垂直列上)。

该规则会把它们统一整理成规范形态。源码实现位于 src/Fixer/Phpdoc/AlignMultilineCommentFixer.php,测试位于 tests/Fixer/Phpdoc/AlignMultilineCommentFixerTest.php,后者定义的每一个用例都属于官方向后兼容承诺的一部分。

可配置项 comment_type:三种修复范围

该规则是CONFIGURABLE(可配置)的,唯一选项为comment_type,官方文档给出的定义如下:

取值含义处理对象
phpdocs_only(默认)只修复 PHPDoc 注释T_DOC_COMMENT
phpdocs_like修复所有"每一行都以星号开头"的多行注释T_DOC_COMMENT+ 符合形态的T_COMMENT
all_multiline修复所有多行注释T_DOC_COMMENT+ 所有T_COMMENT
  • 允许的值'all_multiline''phpdocs_like''phpdocs_only'
  • 默认值'phpdocs_only'

从源码看,该配置直接决定了 fixer 的候选 Token 范围。configurePostNormalisation()方法(见 src/Fixer/Phpdoc/AlignMultilineCommentFixer.php)总是把T_DOC_COMMENT纳入tokenKinds,只有comment_type不等于phpdocs_only时才追加T_COMMENT;而isCandidate()则依据这两个 Token 类型判断文件是否值得处理(同文件 L109-L112)。选项的合法性校验通过FixerOptionBuilder::setAllowedValues()完成(L177-L185),传入非法值时抛出InvalidFixerConfigurationException——测试testInvalidConfiguration已验证这一行为(见 tests/Fixer/Phpdoc/AlignMultilineCommentFixerTest.php)。

三种配置的差异本质

三种模式在处理普通多行注释(T_COMMENT)时行为不同,这正是phpdocs_likeall_multiline的关键区别。看源码applyFix()中的守卫条件(L146-L148):

  • 对于T_COMMENT,当comment_type不是all_multiline时,如果注释内容中存在"空行、或以非星号字符开头的行",则该注释整体被跳过、不修复;
  • 而当comment_typeall_multiline时,这个守卫被绕过,所有多行注释都被纳入修复。

也就是说:phpdocs_like只收拾"看起来像 DocBlock 的块注释"(每一行都规规矩矩以星号开头,只是对齐不齐),而all_multiline连"内部混有裸文本行"的块注释也会强行改造。

三个官方示例详解

文档给出了三个 diff 形式的示例,下面逐一说明。

示例 #1:默认配置phpdocs_only

输入:

<?php /** * This is a DOC Comment with a line not prefixed with asterisk */

输出:

<?php /** * This is a DOC Comment * with a line not prefixed with asterisk * */

这是最典型的场景:/**T_DOC_COMMENT,被默认配置命中。所有后续行统一补上星号、并以首行缩进对齐。注意空行也被补成了*(单独一个星号的行)。

示例 #2:['comment_type' => 'phpdocs_like']

输入:

<?php /* * This is a doc-like multiline comment */

输出:

<?php /* * This is a doc-like multiline comment */

这里注释以/*开头,属于普通注释(T_COMMENT),但内部每一行都以星号开头,形态上"像 PHPDoc",因此被phpdocs_like选中并对齐。测试用例也验证了该行为:tests/Fixer/Phpdoc/AlignMultilineCommentFixerTest.php中有一组用例专门确认phpdocs_like会把/*\n * Doc-like Multiline comment\n *\n*\n */中对不齐的星号统一到同一列(见测试文件 L76-L90)。

示例 #3:['comment_type' => 'all_multiline']

输入:

<?php /* * This is a doc-like multiline comment with a line not prefixed with asterisk */

输出:

<?php /* * This is a doc-like multiline comment * with a line not prefixed with asterisk * */

与前一个示例对比可见:多了一行"以裸文本开头"的内容,在phpdocs_like下整块注释会被跳过,但在all_multiline下会连裸文本行一起补上星号并对齐。测试文件中的另一组用例(L117-L133)同样验证了all_multiline对混有裸文本行的块注释会进行全量修复。

源码级原理:修复是如何逐行完成的

深入 src/Fixer/Phpdoc/AlignMultilineCommentFixer.php 的applyFix()方法,可以看到完整修复流程:

  1. 读取行结束符:通过whitespacesConfig->getLineEnding()获取项目配置的换行符(\n\r\n)。测试中专门用new WhitespacesFixerConfig("\t", "\r\n")验证了 CRLF 环境下输出保持\r\n(见测试 L66-L74)。
  2. 定位注释 Token:遍历 Token 流,只处理tokenKinds命中的注释 Token;通过向前查看 Token 收集注释前的空白与缩进。若注释紧跟在T_OPEN_TAG后,还会用Preg::replace('/\S/', '', ...)把开标签行内非空白字符清掉来叠加计算缩进,保证文件开头无换行的注释也能正确对齐。
  3. 计算基准缩进:用正则/\R(\h*)$/从注释前的空白中取出最后一行的水平缩进,作为对齐基准;若取不到(注释不在新行起始处),则跳过该注释。
  4. 逐行重组:按换行符拆分注释内容,对除第一行外的每一行:
    • ltrim去掉行首空格;
    • T_COMMENT下若该行不以*开头则跳过(与上文phpdocs_like守卫配合);
    • 空行补成*,非星号开头的行补成*前缀;
    • 最终统一写成缩进 + ' ' + 行内容
  5. 回写 Token:用implode($lineEnding, $lines)拼接后构造新 Token 替换原 Token。

值得注意的是,修复基准始终取"注释 Token 前一行"的缩进,而不是某个固定列,因此无论注释位于顶层、类内还是数组元素之间,都能跟随上下文缩进对齐。

与其他规则的执行顺序(Priority)

align_multiline_comment的优先级为27(见 getPriority()),其文档注释明确了执行顺序约束:

  • 必须运行在ArrayIndentationFixer之后:因为数组缩进修复后,注释的基准缩进才是最终值。仓库中的集成测试tests/Fixtures/Integration/priority/array_indentation,align_multiline_comment.test直接验证了这一顺序——输入中注释被过度缩进到与数组值平齐,array_indentation先把/*拉回正确缩进,随后align_multiline_comment把内部星号对齐到同一列。
  • 必须运行在大量 phpdoc 类 fixer之前(包括PhpdocAlignFixerPhpdocTrimFixerPhpdocSummaryFixerPhpdocSeparationFixerNoEmptyPhpdocFixerPhpdocToCommentFixer等 30 余个):因为这些规则大多假设注释已经是"每行带星号"的规范形态。例如集成测试tests/Fixtures/Integration/priority/align_multiline_comment,phpdoc_trim_consecutive_blank_line_separation.test表明:先由align_multiline_comment把空行统一成*,再由phpdoc_trim_consecutive_blank_line_separation裁剪连续空行,二者协作才能得到干净的 DocBlock。

规则集归属与启用方式

align_multiline_comment是以下两个官方规则集的组成部分(见文档 doc/rules/phpdoc/align_multiline_comment.rst 的 Rule sets 一节):

  • @PhpCsFixer(对应规则集文档 doc/ruleSets/PhpCsFixer.rst)
  • @Symfony(对应 doc/ruleSets/Symfony.rst)

从源码看,@Symfony规则集定义中直接以'align_multiline_comment' => true启用(见 src/RuleSet/Sets/SymfonySet.php);而@PhpCsFixer通过'@Symfony' => true继承@Symfony并追加更多规则(见 src/RuleSet/Sets/PhpCsFixerSet.php),因此该规则对两个规则集都生效。

通过规则集启用

在项目根目录的.php-cs-fixer.php配置文件中:

<?php return (new PhpCsFixer\Config()) ->setRules([ '@Symfony' => true, // 或 '@PhpCsFixer' => true ]) ->setFinder( PhpCsFixer\Finder::create()->in(__DIR__) );

单独启用并定制 comment_type

<?php return (new PhpCsFixer\Config()) ->setRules([ 'align_multiline_comment' => [ 'comment_type' => 'phpdocs_like', // 或 'phpdocs_only' / 'all_multiline' ], ]);

命令行使用

也可以在 CLI 中临时指定规则运行:

# 只检查,不修改 php php-cs-fixer fix path/to/file.php --dry-run --rules='{"align_multiline_comment": {"comment_type": "phpdocs_like"}}' # 实际修复 php php-cs-fixer fix path/to/file.php --rules='{"align_multiline_comment": true}'

边界行为:哪些注释不会被触碰

综合测试用例(见 tests/Fixer/Phpdoc/AlignMultilineCommentFixerTest.php),以下几类注释会原样保留

  • 单行注释/** inline doc comment */这类单行 DocBlock,以及#//开头的单行注释,均不处理;
  • 不在新行起始处的注释:如$a=1; /** ... */后跟的多行注释(无法稳定提取基准缩进);
  • 形态不匹配的块注释:默认配置下,phpdocs_only只处理真正的 DocBlock;phpdocs_like会跳过内部存在空行或裸文本行的块注释;
  • 包含多字节字符的注释:测试中有专门命名为uni code test的用例(L257-L273),确认对包含西里尔字母等 Unicode 内容的注释只对齐星号列、不破坏内容。

小结

align_multiline_comment是 PHP-CS-Fixer 在注释规范化层面的一道基础工序:它把"星号缺失、列不对齐"的多行注释统一成 PSR-5 风格的规范 DocBlock。通过comment_type一个选项即可精确控制作用范围——默认只动真正的 PHPDoc,phpdocs_like覆盖"形似 PHPDoc"的块注释,all_multiline则无差别处理所有多行注释。配合其 27 的优先级设计(数组缩进之后、其他 phpdoc 规则之前),它能与其他规则无缝衔接,因此被@Symfony@PhpCsFixer两大主流规则集默认收录,是保证团队注释风格一致性的低成本高收益选择。

  • 开发工具
  • 代码质量
  • 静态分析
  • Lint
  • 格式化

【免费下载链接】PHP-CS-Fixer

A tool to automatically fix PHP Coding Standards issues

项目地址:https://gitcode.com/gh_mirrors/ph/PHP-CS-Fixer
点击查看免费下载

相关推荐

上一篇:Conductor工作流异常监控:告警级别与通知渠道配置
下一篇:EmDash 文档反 AI 味编辑指南:从 anti-slop.md 到可执行的去水检查流程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询