在项目和团队之间共享 PHP-CS-Fixer 规则
发布时间 作者 timacdonald
PHP-CS-Fixer 是一款开源工具,可以强制执行和检测 PHP 代码风格的违规行为。通过预定义的规则,它允许您拥有严格的代码风格,由工具强制执行,以便您将更多时间花在更重要的事情上。
规则示例
以下是一些 PHP-CS-Fixer 可以对您的代码库进行的操作示例。
规则:is_null
用 $var === null
替换 is_null($var)
表达式。
// before...if (is_null($account->closed_at)) { //} // after...if ($account->closed_at === null) { //}
规则:mb_str_functions
用相应的 mb 函数替换非多字节安全的函数。
// before...$length = strlen($request->post('slug')); // after...$length = mb_strlen($request->post('slug'));
规则:not_operator_with_successor_space
逻辑 NOT 运算符 (!)
应该带有一个尾随空格。
// before...- if (!$user->is_active) { //} // after...if (! $user->is_active) { //}
可用的规则非常全面,并且数量还在不断增加。您可以在 项目的自述文件 中查看所有可用的规则列表。您可能还想查看 PHP-CS-Fixer 配置器,这是一个网站,它提供每个规则的示例,以防它们的描述不清楚。
小贴士:除了修复样式之外,它通常可以作为升级工具。 PHPUnit 8 为多个方法添加了 void
返回类型。在 /tests
目录上运行 PHP-CS-Fixer 的 void_return
规则可以立即升级您的测试套件,使其与这些更改兼容。
共享您的规则
我在我的所有项目中都使用 PHP-CS-Fixer,并且有一个规则集来定义样式。到目前为止,我一直都是在我开始新项目时复制粘贴我的规则,并且随着新规则的发布,我必须更新我所有现有项目中的配置。这不是一个理想的工作流程,因为您很容易忘记更新特定项目,而且这是一堆手动工作。
事实证明,您可以在多个项目和团队之间共享您的规则,以便 composer update
将在任何时候让您的所有项目使用您规则集的最新版本。
搭建仓库
我们将构建一个 git 仓库来存放我们的共享规则集。要开始,我们将初始化一个本地 git 仓库并创建所需的配置文件。
$ mkdir php-styles $ cd php-styles $ git init $ echo "/composer.lock/vendor/.php_cs.cache" >> .gitignore $ mkdir src $ touch src/rules.php src/helpers.php composer.json
定义您的规则
正如我之前提到的,有一套广泛的规则,并且新版本有时包含新规则,因此我发现跟踪您上次查看可用规则的 PHP-CS-Fixer 版本非常有用。这意味着当您升级到新版本时,您将知道要查看哪些版本以查找您可能希望添加到共享规则集中的新规则。我喜欢将上次查看的版本添加到 rules.php
文件的顶部。
<?php // last reviewed: v2.16.3 Yellow Bird
接下来,我们要让 rules.php
文件返回一个包含我们规则集的数组。将规则放在单独的文件中很方便,因为根据您的规格,列表可能会变得非常长。它还允许其他开发人员拉取您的规则集并将它们与他们自己的规则集合并,例如,如果您想拉取 Laravel 代码标准并将其与您团队的一些额外标准组合起来。
<?php // last reviewed: v2.16.3 Yellow Bird return [ '@PSR2' => true, 'array_syntax' => ['syntax' => 'short'], 'final_class' => false, 'new_with_braces' => true, // ...];
PHP-CS-Fixer 带有一些预定义的规则集。与 PSR-2 标准相关的所有规则都捆绑在规则集 @PSR2
中。这允许我们选择标准,而无需单独指定每个规则。
某些规则与其选项相关联。array_syntax
规则允许您指定是否要使用短数组语法或长数组语法。
其他规则在列表中通过使用它们的名称和一个布尔值来指定,如 new_with_braces
规则所示。虽然您可以省略布尔值,但我喜欢将其包含在内以保持一致性,因此数组中的每个项都是一个 key ⇒ value
对,因此我知道我已经明确地排除了特定规则。
辅助方法
为了使在您的项目中使用您的共享规则变得轻松,我们将创建一个辅助函数。您可能现在还不知道为什么要这样做,但请继续关注,一切都会水到渠成。
为了确保该函数不会与您项目或其依赖项中的任何其他全局函数发生冲突,最好将该函数放在命名空间中。打开 helpers.php
文件并定义一个适合您的上下文的命名空间。
<?php namespace TiMacDonald;
现在我们需要定义方法签名。该方法将接受一个 PhpCsFixer\Finder
实例,以及一个规则数组,这将允许项目识别每个项目的基础上任何额外的强制规则。通常,我会说我们想要一致性,并且不应该允许每个项目更改共享规则集——但我不会在这里告诉你该怎么做,所以我们会让你这样做,但你始终可以删除该功能,如果这是你的偏好。
<?php namespace TiMacDonald; use PhpCsFixer\Config;use PhpCsFixer\Finder; function styles(Finder $finder, array $rules = []): Config { //}
太棒了。它正在很好地组合在一起。现在最后要做的事情是填充辅助函数的主体。
<?php namespace TiMacDonald; use PhpCsFixer\Config;use PhpCsFixer\Finder; function styles(Finder $finder, array $rules = []): Config { $rules = array_merge(require __DIR__.'/rules.php', $rules); return Config::create() ->setFinder($finder) ->setRiskyAllowed(true) ->setRules($rules);}
$finder
是 PHP-CS-Fixer 知道在哪里查找要修复的 PHP 文件的方式。我们将此决定推迟到项目,因为每个项目可能具有不同的目录结构,例如,Laravel 项目与 Laravel 包相比。
危险规则
在 styles
函数的主体中,您可以看到我们正在告诉配置允许“危险”规则,通过调用 setRiskyAllowed(true)
。您必须阅读文档并了解危险规则如何影响您的项目。例如,我们来看一下 implode_call
规则。如果您阅读了 PHP 文档关于 implode
的内容,您会注意到
implode() 由于历史原因,可以接受其参数以任意顺序排列。但是,为了与 explode() 保持一致性,不使用文档中指定的参数顺序已被弃用。
这意味着这两个 implode 调用将产生相同的结果
<?php implode($array, ','); implode(',', $array);
implode_call
规则将重新排列参数以使其按文档顺序排列,但如果您的项目通过某种方式(例如 runkit)重新定义了 implode()
的行为以按错误顺序预期参数,则更改其顺序可能会破坏您的代码。
因此,请阅读每个危险规则的作用,并了解其工作原理,然后再将其添加到您的规则集中。
composer.json
为了将包拉取到我们的项目中,我们需要填充 composer.json
文件。我建议在持续集成(C.I.)中运行样式检查,因此我将本地包含 PHP-CS-Fixer(如果您有包冲突,您可以选择将 PHP-CS-Fixer 下载为 Phar 文件)。
打开 composer.json
文件,并确保设置一个适合您的唯一 "name"
。
{ "name": "timacdonald/php-style-example", "description": "Tim's shared PHP style rules for PHP-CS-Fixer", "license": "MIT", "require": { "friendsofphp/php-cs-fixer": "^2.0" }, "autoload": { "files": [ "./src/helpers.php" ] }}
将代码推送到代码托管平台
设置代码仓库的最后一步是将其推送到托管的 Git 解决方案。在您选择的代码托管平台上创建一个仓库,并将其添加为本地仓库的远程仓库。我将使用 GitHub。
$ git add . $ git commit -m wip $ git remote add origin [email protected]:timacdonald/php-style-example.git $ git push -u origin master
现在,我们已将共享的规则包发布到 GitHub 上。恭喜!
使用共享规则
现在我们将稍微改变方向,重点介绍如何在其他项目中使用新的共享规则。关闭共享规则仓库,并打开要使用这些规则的项目。有一些初始设置,但完成之后,只需要运行 composer update
命令即可。
引入仓库
Composer 允许我们从托管的 Git 平台引入仓库,而无需将它们提交到 Packagist。考虑到这种类型的仓库很可能是内部的,将其添加到 Packagist 并没有太大好处。
要开始使用,请手动将包名称添加到项目的 "require-dev"
块中。我不需要将我的样式锁定到特定版本,因此我使用 "dev-master"
,这意味着始终会拉取最新的样式。但是,您也可以对样式进行版本控制,这取决于您。
由于我们不会提交到 Packagist,因此必须告诉 Composer 在哪里找到包。我们使用 repositories 块来实现这一点。
"repositories": [ { "type": "vcs", "url": "https://github.com/timacdonald/php-style-example" }]
现在,我们告诉 Composer 将我们的包作为 --dev
依赖项引入。
$ composer require timacdonald/php-style-example --dev
设置 PHP-CS-Fixer Finder 配置
为了让 PHP-CS-Fixer 知道要针对哪些文件,您需要使用 PhpCsFixer\Finder
实例指定每个目录或文件。这是 Symfony\Component\Finder\Finder
的继承版本,因此有关所有可使用约束的完整文档,请 查看文档。
在我们的示例中,我将假装我们正在使用 Laravel 应用程序,并设置 Finder 以搜索我知道要遵守样式规范的目录。
PHP-CS-Fixer 预计您的配置位于 /.php_cs.dist
文件中,因此我们将创建该文件。
$ touch .php_cs.dist
打开此文件并添加以下 Finder 设置,适用于您的 Laravel 应用程序。您也可以包含任何其他要修复的文件夹,但这些是合理的默认值。
<?php $finder = PhpCsFixer\Finder::create() ->in([ __DIR__.'/app', __DIR__.'/config', __DIR__.'/database', __DIR__.'/routes', __DIR__.'/tests', ]);
现在,我们准备好将 Finder 传递给几分钟前创建的辅助函数。PHP-CS-Fixer 预计此文件将返回 PhpCsFixer\Config
的实例,这正是我们的辅助函数返回的内容。
<?php $finder = PhpCsFixer\Finder::create() ->in([ __DIR__.'/app', __DIR__.'/config', __DIR__.'/database', __DIR__.'/routes', __DIR__.'/tests', ]); return TiMacDonald\styles($finder);
现在准备好姿势,我们将自动修复所有这些目录中的编码风格!进入终端并运行以下命令以观察奇迹发生……
./vendor/bin/php-cs-fixer fix
在 CI 中运行
在 CI 过程中执行样式规则是一个好主意。您可以通过几种方式实现:您可以进行“试运行”,如果检测到代码风格违规,则会失败。
./vendor/bin/php-cs-fixer fix --dry-run
或者,您可以让 CI 运行修复器并自动将更改提交到您的仓库。如果您使用 GitHub Actions,请 查看 Stefan Zweifel 撰写的这篇很棒的文章,了解如何实现这一点。
总结
感谢您参与这段旅程。PHP-CS-Fixer 是一款很棒的工具,如果您运行多个共享标准编码风格的项目,那么这种方法可能会派上用场。