编程

引入 PHP-CS-Fixer 到老项目中

884 2023-05-05 02:48:00

你正在处理一个遗留的 PHP项目,并希望使用 friendsofphp/php-cs-fixer 来强制执行一致的编码标准。但你不确定如何在不造成问题的情况下做到这一点。

在遗留 PHP 中引入 PHP CS Fixer 以降低风险并邀请其他开发人员进行合作,应该采取什么样的策略?

要求

如果你想在遗留 PHP 项目中成功地引入 PHP CS Fixer,你将有以下要求:

  • 你希望在持续集成系统中运行 PHP CS Fixer。当提交和推送不符合编码标准的代码时,你希望持续集成系统中的构建失败。
  • 你希望在开发环境中运行 PHP CS Fixer。当更改 PHP 代码和不符合编码标准的代码时,你希望 PHP CS Fixer 修复违反编码标准的问题。你不需要在开发环境中报告违反编码标准的情况;你想直接去修复。你还需要一个简单的命令来在开发环境中运行 PHP CS Fixer,这样就可以频繁地运行它。
  • 你希望 PHP CS Fixer 只应用与你在生产中使用的 PHP 版本兼容的修复程序。如果项目运行在 PHP 5.3 上,你不希望 PHP CS Fixer 将需要运行在 PHP 8.1 上的修复程序在 5.3 上运行。

安装  PHP-CS-Fixer

你可以使用 composer、phive 或从发布页面下载 PHAR 来安装 PHP CS Fixer。但你可以在 PHP CS Fixer 的 README.md 中详细研究 PHP CS Fixter 的安装选项和说明;我不会在这里重复。

我建议使用 composer 来安装 PHP CS Fixer,这样就可以从可靠的、Renovatebot 或类似服务的自动依赖更新中受益。如果使用 phive 安装 PHP CS Fixer 或从发布页面下载,则必须手动更新 PHP CS Fixer。

你的项目还没有使用 composer?为什么不通过将 PHP CS Fixer 作为第一个开发依赖项来开始使用 composer 呢?

你不能使用composer,因为项目在生产中还没有在 PHP 5.3 上运行?为什么不使用不同版本的 PHP 来运行开发工具呢?

我还建议使用最新版本的 PHP CS Fixer,这样就可以从维护人员和贡献者不断添加到工具中的功能和修复中受益。

你不能使用最新版本的 PHP CS Fixer,因为项目还没有在生产中运行 PHP 7.4 或更高版本?同样,为什么不使用不同版本的 PHP 来运行开发工具呢?

例如,在过去的几周里,我一直忙于将一个项目从 PHP 5.6 升级到 PHP 8.1。在 Docker 中设置了一个在 PHP 5.6 上运行的本地开发环境后,我已经建立了一个 GitHub Actions 工作流,该工作流使用 PHP 8.1 安装和运行开发工具,包括 PHP CS Fixer。

如果我可以使用 PHP 8.1 为一个在生产中运行 PHP 5.6 的项目运行开发工具,那么你也可以。

成功的关键是对开发工具进行仔细的配置。

为 PHP-CS-Fixer 添加一些基础配置 

PHP CS Fixer 需要两件事来报告和修复违反编码标准的行为:一份应该检查的文件列表,以及一份用于创建和配置相应修复程序的规则和规则集的配置。

下面的配置文件 .php-cs-fixer.php 配置了一个查找器和一个空的规则数组。

<?php

$finder = PhpCsFixer\Finder::create()
    ->exclude([
        '.build/',
        '.docker/',
        '.github/',
    ])
    ->ignoreDotFiles(false)
    ->in(__DIR__)
    ->name('.php-cs-fixer.php');

$config = new PhpCsFixer\Config();

$config
    ->setFinder($finder);
    ->setRules([]);

return $config;

finder 允许你配置目录、排除项、文件名等的列表,并返回 PHP-CS-Fixer 应该检查的文件列表。

根据项目布局,你的 finder 配置可能会有所不同。

空的规则数组将覆盖默认规则配置。PHP CS Fixer 在应用修复程序之前和之后对 PHP 文件进行 lint 处理,以确保它既不会试图修复包含无效PHP 代码的文件,也不会留下包含无效 PHP 码的文件。当 PHP CS Fixer 发现一个文件不包含有效的 PHP 代码时,它将跳过修复并发出警告。

即使使用一个空的规则数组,PHP CS Fixer 对你来说也是一个很有价值的工具,因为它可以帮助你找到包含无效 PHP 代码的文件。

既然有了 PHP-CS-Fixer 初始配置,我们开始运行 PHP-CS-Fixer 吧。

在 GitHub Action 中运行 PHP-CS-Fixer

如前所述,你会在两个环境中运行 PHP-CS-Fixer:你的持续集成(CI)系统中和本地开发环境中。

下面的命令会使用 --dry-run 选项运行 PHP-CS-Fixer,并报告代码标准违规:

vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff --dry-run --verbose

根据安装 PHP CS Fixer 和命名配置文件的方式,该命令可能会有所不同。

但在连续集成系统中运行 PHP CS Fixer 时,使用 --dry-run 选项很重要:当发现违反编码标准构建时,PHP CS Fixer 将以非零退出码结束执行并退出构建。

我在 GitHub 感到宾至如归,喜欢使用 GitHub Actions 作为一个持续集成系统。下面的 GitHub Action 工作流将检查你的 repository 存储库,设置 PHP,使用 composer 安装依赖项,并使用 --dry-run 选项运行 PHP CS Fixer。

name: "Integrate"

on:
  pull_request: null
  push:
    branches:
      - "main"

jobs:
  coding-standards:
    name: "Coding Standards"

    runs-on: "ubuntu-latest"

    strategy:
      matrix:
        php-version:
          - "8.1"

    steps:
      - name: "Checkout"
        uses: "actions/checkout@v3.5.0"

      - name: "Set up PHP"
        uses: "shivammathur/setup-php@v2.24.0"
        with:
          coverage: "none"
          php-version: "${{ matrix.php-version }}"

      - name: "Validate composer.json and composer.lock"
        run: "composer validate --ansi --no-check-publish"

      - name: "Install locked dependencies with composer"
        run: "composer install --ansi --no-interaction --no-progress"

      - name: "Run friendsofphp/php-cs-fixer"
        run: "vendor/bin/php-cs-fixer fix --ansi --config=.php-cs-fixer.php --diff --dry-run --verbose"

根据你的项目设置和持续集成系统,配置可能会有所不同,但步骤大致相同。

有了这个 GitHub Actions 工作流,你就无法提交和推送不符合您的编码标准的 PHP 代码而不造成编译失败。

💡 你可以通过在缓存 composer 安装的依赖项和 PHP-CS-Fixer 的缓存文件来改进 coding-standards 任务。

在开发环境中运行 PHP-CS-Fixer

下面命令会运行 PHP-CS-Fixer 并修复违反代码标准的问题:

vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff --verbose

根据你安装 PHP CS Fixer 和命名配置文件的方式,该命令可能会有所不同。同样,你不关心在开发环境中报告违反编码标准的情况;你将直接进行修复。

该命令键入起来有点长,如果你想经常运行 PHP CS Fixer,你可能想使用任务运行程序或其他一些工具,这样可以更容易地在开发环境中运行工具。

如果使用 Makefile,请将编码标准目标添加到 Makefile 中。

.PHONY: coding-standards
coding-standards: vendor
	vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff --verbose

vendor: composer.json composer.lock
	composer validate --strict
	composer install --no-interaction --no-progress

有了 Makefile 中的编码标准目标,你可以运行以下命令,让 PHP CS Fixer 修复违反编码标准的问题:

make coding-standards

💡 如果你还没有使用 Makefile,或者发现命令仍然太长,请阅读懒人版 Makefile 手册。

如果你更喜欢 composer 脚本,请在 composer.json 中添加一个编码标准脚本。 

如果你偏向于 Composer 脚本, 添加 code-standards 脚本到你的 composer.json。

{
  "scripts": {
    "coding-standards": "@php vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff --verbose"
  }
}

在你的 composer.json 中有了 code-standard 脚本,你可以运行如下命令让 PHP-CS-Fixer 修复违反代码标准的问题:

composer coding-standards

PHP CS Fixer 配置的演变

现在,你已经在持续集成系统和开发环境中运行 PHP CS Fixer,还剩一件事:你希望 PHP CS Fixer 使用与你在生产中使用的 PHP 版本兼容的修复程序,而到目前为止,你只配置了一个空的规则数组。

以下是对我有效的方法。

首先,获取所有可用修复程序的完整规则列表,例如,来自 lergebnis/php-cs-fixer-config-template 的自定义规则集。

其次,调整规则配置以进行配置,但禁用所有这些修复程序。在撰写本文时,应该有 250 条规则。

<?php

$finder = PhpCsFixer\Finder::create()
    ->exclude([
        '.build/',
        '.docker/',
        '.github/',
    ])
    ->ignoreDotFiles(false)
    ->in(__DIR__)
    ->name('.php-cs-fixer.php');

$config = new PhpCsFixer\Config();

$config
    ->setFinder($finder);
    ->setRules([
        'align_multiline_comment' => false,
        'array_indentation' => false,
        'array_push' => false,
        'array_syntax' => false,
        // ...
        'visibility_required' => false,
        'void_return' => false,
        'whitespace_after_comma_in_array' => false,
        'yoda_style' => false,
   ]);

return $config;

💡 或者,如果你已经跨项目共享 PHP CS Fixer 的配置,如跨项目共享 PHP CS Fixer 配置中所述,请通过禁用所有规则来覆盖现有的规则配置。

第三,从上到下或从下到上,看你哪个更适合你,浏览规则列表,选择一个规则,仔细检查它的文档,并一次启用和配置一个规则-但前提是您可以确保它只应用与生产中运行的 PHP 版本兼容的修复程序。

一次启用和配置一条规则的示例

让我们看看具体的例子,当您处理拉取请求和合并前代码审查时,考虑并配置 array_syntax 规则。

  • 首先,创建一个分支,比如 feature/array-syntax
  • 其次,辅助规则名称。
  • 第三,导航到 https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.16.0(将 3.16.0 替换为你实际使用的 PHP CS Fixer 版本)。按 T 键打开文件导航。将规则的名称粘贴到输入字段中(此处为 array_syntax)。在下拉列表中选择相应的文档文件(此处为 array_syntax.rst)。
  • 第四,检查文件。你能安全地启用 array_syntax 修复程序吗?例如,PHP 5.4 引入了短数组语法。你的遗留 PHP 项目是否在生产中运行在 PHP 5.3 上?然后,您可能应该启用 array_syntax 修复程序,并将语法选项配置为使用 long 作为值。或者你的遗留 PHP 项目是否运行在 PHP 5.4 或更高版本上?然后,你可能应该启用修复程序,并将语法选项配置为使用 short as value。
  • 第五,将更改提交并推送到 .php-cs-fixer.php 配置文件。
  • 第六,打开一个 pull 请求,并在正文中说明这个 pull 请求将启用 array_syntax 修复程序。打开拉取请求将启动 GitHub Actions 工作流的运行。
  • 第七,在开发环境中运行 PHP CS Fixer。如果 PHP CS Fixer 已经应用了修复程序,那么 GitHub Actions 工作流将失败。提交并在单独的提交中推送修复程序,以使构建通过。
  • 第八,审查拉取请求中的更改,并验证这些更改是否合理。如果有必要,让其他人也审查你的 PR 请求。
  • 第九,合并拉取请求并删除分支。
  • 第十,检查开发环境中的默认分支。
  • 第十一,拉取最新变化。
  • 第十二,删除特征分支。

为每个规则重复上述动作。

一次启用和配置一条规则的缺点

在撰写本文时,PHP CS Fixer 附带了 250 条规则。一次启用和配置一个规则可能需要一段时间,尤其是当你处理拉取请求并需要进行合并前代码审查时。但是,你可以通过使用 Ship/Show/Aask 显著加快流程。

如果你不愿意投入时间,可以一次应用所有规则并审查所有修复,祝你好运!

一次启用和配置一个规则的优点

在我看来,一次启用和配置单个规则具有以下优势:

  • 你可以最大限度地降低风险:每个拉取请求只包含更容易审查的相关更改。

你邀请其他开发人员就你的编码标准进行合作。

你可能会在遗留 PHP 项目各个角落的代码修改代码,这使你能够发现并注意到需要仔细检查的奇怪地方。

 

PHP