本文旨在确认 PHPLint、PHP-CS-Fixer 和 PHP_CodeSniffer 的差异,根据当前公司的需求进行选择,并编写一个简单的自定义规则。
Lint 工具浅析
PHPLint 是三者中我唯一用过的 Lint 工具,另外两个则是较为出名的 PHP 领域的自动化语法规范或静态错误定位工具。
每个工具都在安装、运行的基础上,测试三块:
- 展示错误,自动修复(如果有这个功能)
- 某一行代码跳过特定检测
- 切换规则集合。
- 关闭一条规则。
- 写一个自定义规则。
参考开源社区的活跃程度,本次主要的探索点也会放在后两者上。
PHP-CS-Fixer
环境说明,PHP 7.4 是它所需的最低版本。
提一嘴:请保证你的 PHP 最少处于 LTS 版本中,否则它将失去后续的安全补丁。
它支持多种安装方式:PHAR、Composer 等等。
通过 composer require friendsofphp/php-cs-fixer
安装,然后跑起来:vendor/bin/php-cs-fixer fix some_path
。
如果你装在全局,就不需要调用 vendor 目录的执行文件,不过考虑一下规范是否是全局的,否则写个 Shell 更合适。
展示错误,自动修复
以我写的 Laravel Demo 为例:vendor/bin/php-cs-fixer fix app/Http/
,成功将我的 if (expression) once_line_code 给转化掉了,没啥毛病。
使用 vendor/bin/php-cs-fixer fix app/Http --dry-run --diff
,这样不会修改文件,并能获取检测结果的具体问题和推荐修改。
某一行代码跳过特定检测
基于 Issue 4512,暂不支持。
切换规则集合
通过 /.php-cs-fixer.dist.php
,你可以方便的定义自己的配置文件——里面涵盖了具体规则、规则集合、待检查的文件目录、剔除检查的目录等的变更。
简单的尝试:替换为 PSR12 并开启不安全修复模式,没问题。
关闭某条规则
这个工具采用的是最小规则默认,所以在配置文件中不包含,就可以放弃对应规则的检测。
CI
官方提供了对应的命令,使你高效的将其纳入 CI 构建流程。
编写自定义规则
尝试添加了一条 App/test_rule
规则。优点如下:
- 编写简单,在接口约束的前提下,基本上都是可读的 Function 编写;
- 规则存放灵活,规则类可以直接放在任意项目路径下——写个包隔离出去也可以,如果你喜欢;
- 参考性强,尽管缺乏足够的自定义规则编写指南,但你很容易就找到了所有的规则类,阅读、理解、编程,很好的循环。
- 基本上遵循
\PhpCsFixer\Fixer\FixerInterface
接口即可,更多的自行参考文档。
PHP_CodeSniffer
环境说明,PHP 5.4 是它所需的最低版本,但特定规则需要更高版本的 PHP 支持。
与 CS-Fixer 类似,也提供了多种安装方式,老样子:
composer require "squizlabs/php_codesniffer=*"
展示错误,自动修复
以我写的 Laravel Demo 为例:./vendor/bin/phpcs app/Http/
。
显示出了密密麻麻的错误数量提示:Line | Level | Message。很好,有 PHPLint 的味道了。
它的一个工具:phpcbf
可以让你自动修复发现的问题——如果能自动修复的话。
如果我们希望接入 CI,PHP CS 提供了对应的 Action,你可以将其融入到构建流程。
某一行代码跳过特定检测
CS 提供了跳过文件、跳过某行、暂时关闭,乃至下一行不检测某个规则。
简单测试了上述的,譬如通过 // phpcs:ignore
,可以跳过某行检测,从文档里你可以找到更多、更详细的解释。
切换规则集合
通过 .phpcs.xml
或类似的文件(它竟然支持数个不同的名字……),我们可以定义配置:
<rule ref="/path/to/standards/Generic/Sniffs/Commenting/TodoSniff.php"/>
这样就添加了对应的 ToDo Sniff 规则。
关闭某条规则
与 CS Fixer 一致,只要不包含对应规则即可。我们感受到它默认支持很多规则,是因为它的默认配置比较全面。
命名相较 CS Fixer 更简单,但规则列表比较难找。
CI
PHP CS 官方支持的是 Github CI Action,对于分发和 diff 需求,并没有合适的支持。
尽管如此,你可以通过 diffFilter 为其提供基于 commit 或 PR 范围的合理提示。
尝试了一下,调整 Shell 和钩子相比较 PHP CS Fixer 略微耗时。
编写自定义规则
CS 将规则称呼为嗅探器(Sniff),支持 PSR2、PSR12 等通用规则。感觉规则比 Fixer 提供的少一些,不过没关系,我们来尝试添加了一条 test_rule
规则。
首先指出,CS 有完整地 Step-To-Step 教程指导你如何写自己的规则,如果你希望使用 CS 在自己的技术栈中,推荐直接阅读它(官方的 Wiki 指南),而不是我这样的博客文章。
开工。
首先,让我们像 Fixer 一样,在项目中直接创建自己的规则目录和文件,保持灵活的同时,后期依旧可以将其抽离为 Composer Package。
我们管容纳自定义规则集合、定义文件等的目录叫 MyStandard
,进入其中并创建 ruleset.xml
——它可以定义规则具体的条件。
格式大略为:
<?xml version="1.0"?>
<ruleset name="MyStandard">
<description>A custom coding standard.</description>
</ruleset>
所以,这个规则就被称为 MyStandard 规则集,里面将包含一个或若干的实际嗅探器来执行检查。
接着创建目录 MyStandard/Sniffs
,为了不让你困惑,我直接用嵌套结构表示它的实际位置。这里将容纳嗅探器文件。
然后我们对评论进行嗅探,继续创建目录 MyStandard/Sniffs/Commenting
,在其中创建 DisallowHashCommentsSniff.php
嗅探器(文件)。
Sniffs 下的目录其实不重要,只是为了方便我们将更多嗅探器区分开,你如果喜欢,也可以将百十来个规则丢在一起,实现软件工程师们深恶痛绝的“大杂烩”(:D)。
与 Fixer 一样,它也规定了一个接口——Only Once,PHP_CodeSniffer\Sniffs\Sniff
,继承并实现关键方法就好。
supportedTokenizers
属性定义:嗅探的文件类型,PHP、JS、Rust、etc.register
方法定义:嗅探的代码类型,单行注释、多行注释、单行代码、代码块、etc.process
方法定义:实际的错误检查、处理。- 系统提供了
addError / addWarning
作为报错信息的添加方法。
- 系统提供了
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$stackPtr]['content']{0} === '#') {
$error = 'Hash comments are prohibited; found %s';
$data = array(trim($tokens[$stackPtr]['content']));
$phpcsFile->addError($error, $stackPtr, 'Found', $data);
}
}
最终,我们采用 phpcs --standard=/path/to/MyStandard has_error_code.php
尝试检测一个 has_error_code.php
文件,里面包含了一些错误。
/path/to/MyStandard
定义了我们规则集合的位置,以帮助 CS 寻找包外的规则集。
试试看吧!
最后,嗅探的文件类型不支持 Rust,那是开玩笑的——尽管你可以让它支持——这很诡异。
无论怎样,更喜欢哪个工具,都祝你玩的愉快!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。