
代码能跑和代码“好”之间隔着一条叫“质量”的河。刚工作那几年我写代码的原则是“能跑就行”。后来接手了一个离职同事的项目打开代码库的那一刻我终于理解了什么叫“屎山”——没有类型声明、没有注释、函数动辄三四百行、全局变量满天飞。改一个bug要花半天时间搞清楚这段代码到底在干什么。从那以后我开始重视代码质量。但一个人的自觉是靠不住的需要工具来约束。经过几年的摸索我搭建了一套从本地开发到CI/CD的PHP代码质量防护体系今天分享出来希望能帮你少走弯路。一、静态分析让bug死在编译前PHP是动态语言很多错误只有在运行时才会暴露。变量名拼写错误、方法不存在、类型不匹配——这些低级bug往往要等到测试甚至生产才被发现。静态分析工具可以在不运行代码的情况下扫描出这些问题。1.1 PHPStan级别越高越严格PHPStan是当前最流行的静态分析工具用级别控制严格程度0-9级9最严。安装composer require --dev phpstan/phpstan配置phpstan.neonparameters: level: 6 paths: - src - tests checkMissingIterableValueType: true checkGenericClassInNonGenericObjectType: true运行vendor/bin/phpstan analyse常用级别level 0最基础只检查最简单的错误如未定义的变量。level 6检查所有方法返回值类型、参数类型。level 9极严格要求所有地方都有类型声明且不能有mixed。我建议从级别5或6开始等代码逐渐规范后再提高。常见问题解决如果代码中有大量mixed可以用var注解帮助PHPStan推断/** var arrayint, User $users */ $users $this-db-query(...);对于第三方库缺少类型定义可以安装对应的stub包或编写自己的stub文件。1.2 Psalm更激进的类型检查Psalm是另一个强大的静态分析工具比PHPStan更激进对类型要求更严格且提供了更多的检查和修复能力。安装composer require --dev vimeo/psalm初始化vendor/bin/psalm --init这会生成psalm.xml配置文件。可以调整errorLevel1最严8最松。运行vendor/bin/psalm特色功能自动修复vendor/bin/psalm --alter --issuesMissingReturnType可以自动添加返回类型。对泛型、模板的支持比PHPStan更好。选择建议如果项目是从头开始可以尝试Psalm它更能推动你写出类型安全的代码。如果是老项目改造PHPStan的级别递增策略更友好。1.3 两种工具一起用可以一起用但会有重复劳动。大多数团队选择其一。我个人的经验PHPStan 高级别 严格模式已经足够。二、代码风格让团队写一样的代码代码风格统一不是为了好看而是为了减少无意义的争论让代码审查聚焦于逻辑而非格式。2.1 PHP_CodeSniffer安装composer require --dev squizlabs/php_codesniffer使用PSR-12规范vendor/bin/phpcs --standardPSR12 src/自动修复vendor/bin/phpcbf --standardPSR12 src/自定义规则可以在.phpcs.xml中配置例如关闭某条规则?xml version1.0? ruleset nameMyProject rule refPSR12/ rule refPSR1.Methods.CamelCapsMethodName exclude-pattern*/tests/*/exclude-pattern /rule /ruleset2.2 PHP-CS-Fixer另一个选择更灵活支持大量规则也可以自动修复。安装composer require --dev friendsofphp/php-cs-fixer配置.php-cs-fixer.php?php return (new PhpCsFixer\Config()) -setRules([ PSR12 true, array_syntax [syntax short], no_unused_imports true, ordered_imports true, ]) -setFinder(PhpCsFixer\Finder::create()-in(__DIR__ . /src));运行vendor/bin/php-cs-fixer fix --dry-run # 检查 vendor/bin/php-cs-fixer fix # 自动修复选择两个工具都能满足需求。PHP_CodeSniffer检查更严格但修复能力弱PHP-CS-Fixer修复能力强但规则配置略复杂。我推荐PHP-CS-Fixer因为它能自动修复绝大多数格式问题省去手动调整的麻烦。三、静态分析实战从一段烂代码开始假设我们有这样一段代码?php class UserService { public function getUsers($ids) { $result []; foreach ($ids as $id) { $user $this-findUser($id); $result[] $user; } return $result; } private function findUser($id) { return DB::query(SELECT * FROM users WHERE id $id)-fetch(); } }运行PHPStan级别6会报出多个错误$ids 没有类型声明。findUser 没有返回类型。可能SQL注入直接拼接变量。fetch()可能返回false但代码没有处理。根据PHPStan的提示我们逐条修复?php class UserService { /** * param int[] $ids * return User[] */ public function getUsers(array $ids): array { $result []; foreach ($ids as $id) { $user $this-findUser($id); if ($user null) { continue; // 或者记录日志 } $result[] $user; } return $result; } private function findUser(int $id): ?User { $stmt DB::prepare(SELECT * FROM users WHERE id ?); $stmt-execute([$id]); $data $stmt-fetch(); if ($data false) { return null; } return new User($data); } }现在代码健壮多了。静态分析就像一位严格的老师逼着你写出更好的代码。四、集成到CI/CD让质量成为红线本地检查再严格也挡不住有人跳过。真正的质量保证要在CI/CD流水线中强制执行。4.1 GitHub Actions 示例创建一个 .github/workflows/quality.yml 文件name: Code Quality on: [push, pull_request] jobs: php-cs-fixer: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - uses: shivammathur/setup-phpv2 with: php-version: 8.2 tools: composer - run: composer install --no-progress - name: Check coding style run: vendor/bin/php-cs-fixer fix --dry-run --diff phpstan: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - uses: shivammathur/setup-phpv2 with: php-version: 8.2 tools: composer - run: composer install --no-progress - name: PHPStan run: vendor/bin/phpstan analyse --no-progress phpunit: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - uses: shivammathur/setup-phpv2 with: php-version: 8.2 tools: composer - run: composer install --no-progress - name: Run tests run: vendor/bin/phpunit这样每次提交代码GitHub都会自动运行代码风格检查、静态分析和单元测试。任何一项失败PR就不能合并。4.2 Git Hooks本地检查对于不想等CI跑完才发现问题的同学可以配置Git Hooks在提交前自动检查。使用pre-commit工具bash# 安装 pre-commit pip install pre-commit # 在项目根目录创建 .pre-commit-config.yaml示例配置repos: - repo: local hooks: - id: php-cs-fixer name: php-cs-fixer entry: vendor/bin/php-cs-fixer fix --dry-run language: system files: \.php$ - id: phpstan name: phpstan entry: vendor/bin/phpstan analyse language: system files: \.php$五、度量与可视化让质量看得见除了检查还可以收集度量数据比如代码复杂度、重复率、测试覆盖率形成趋势图。PHP Metricsphploc可以统计代码行数、类数、方法数phpmd可以检测代码异味。SonarQube开源平台可以集成PHP工具提供仪表盘展示质量指标。Codecov / Coveralls收集测试覆盖率并在PR中展示变化。5.1 测试覆盖率PHPUnit可以生成覆盖率报告vendor/bin/phpunit --coverage-html coverage/在CI中可以上传到Codecov- name: Upload coverage to Codecov uses: codecov/codecov-actionv3 with: files: ./coverage.xml六、常见问题与避坑指南6.1 静态分析对老项目不友好老项目往往缺少类型声明直接运行PHPStan会报几百个错误。解决策略先设置低级别如0逐渐提高。使用基线baselinevendor/bin/phpstan analyse --generate-baseline会生成一个基线文件忽略现有错误只检查新增代码。在phpstan.neon中排除部分目录如tests、legacy。6.2 第三方库缺少类型如果依赖的包没有类型声明可以安装对应的stubs包。例如Laravel有larastanWordPress有php-stubs/wordpress-stubs。6.3 性能问题静态分析工具在大型项目上可能较慢。可以在CI中缓存composer和工具结果。使用--memory-limit提高内存限制。只分析修改的文件高级配置。6.4 与IDE配合安装PHPStan插件如IntelliJ IDEA的PHPStan插件或Psalm插件可以在编写代码时实时看到问题提高效率。七、总结代码质量不是玄学是一套可以工程化落地的体系。从本地开发到CI/CD从静态分析到代码风格从测试到覆盖率——每一步都在为“好代码”投票。回头再看当年接手的那坨“屎山”如果当时有这套工具起码能少掉一半头发。如今PHP 8.6已经发布类型系统越来越强大我们有理由要求自己写出更高质量的代码。最后借用一句话“写代码的时候想象一下接手你工作的人是个知道你住哪的暴力狂。”——开个玩笑但道理是真的善待未来的自己从今天开始用工具武装你的代码。