- 开发工具
【免费下载链接】php-file-iterator
FilterIterator implementation that filters files based on a list of suffixes, prefixes, and other exclusion criteria.
本篇以ergebnis/phpstan-rules的完整变更记录(CHANGELOG.md)为核心骨架,结合其rules.neon参数定义与源码实现,系统梳理这套 PHPStan 扩展规则集从 0.1.0 到 2.14.0 的全部演进脉络:每一条规则何时引入、哪些参数可供配置、PHP 版本与 phpstan/phpstan 依赖如何变迁,以及 0.14.0 那次从Localheinz\PHPStan迁移到Ergebnis\PHPStan的 breaking change 该如何平滑升级。读完你将掌握该扩展的完整规则清单、配置语法(ergebnis参数段)、错误标识符体系,并能在自己的phpstan.neon中精准启停这些规则。作为实例,仓库根目录的 phpstan.neon 与 tools/.phpstan/composer.json 展示了它在 php-file-iterator 项目中的真实落地方式。
一、这份变更记录在讲什么
ergebnis/phpstan-rules是一套面向 PHPStan 的规则扩展包(type: phpstan-extension),通过composer.json的extra.phpstan.includes自动加载rules.neon,为本就强大的 PHPStan 追加一批"编码风格与设计约束"层面的规则。它要求phpstan/phpstan:^2.1.35,支持 PHP 7.4 ~ 8.6 多个大版本(详见 composer.lock 中该包依赖声明)。
本仓库(phpunit/php-file-iterator)将其作为require-dev依赖锁定在2.14.0(见 tools/.phpstan/composer.json 与 composer.lock),并搭配phpstan/phpstan-strict-rules与phpstan/extension-installer使用,PHPStan 分析入口为 tools/phpstan。
变更记录本身遵循两份业界规范:
- Keep a Changelog:按
Unreleased+ 版本号分节,每节内部再按Added(新增)、Changed(变更)、Fixed(修复)、Removed(移除)分类; - Semantic Versioning(语义化版本):
0.x为预发布阶段,1.0.0起承诺向后兼容,2.0.0携带破坏性变更。每个版本条目都附有与前一个版本的 diff 链接,方便审计具体改动。
二、规则全景:从 0.1.0 到 2.14.0 的演进时间线
整套规则的演进可以归纳为五条主题线,下面按主题重组变更记录,并保留版本与引入顺序。
1. 类与继承约束(Classes / Methods)
| 版本 | 规则/变更 | 说明 |
|---|---|---|
| 0.1.0 | Classes\AbstractOrFinalRule | 非匿名类既非abstract也非final时报错 |
| 0.2.0 | Classes\FinalRule | 非匿名类必须final;构造函数增加$excludeClassNames白名单参数 |
| 0.5.0 | 参数allowAbstractClasses、classesNotRequiredToBeAbstractOrFinal | 允许配置FinalRule;AbstractOrFinalRule行为并入FinalRule后被移除,且构造函数默认值被删除(配置必须显式给出) |
| 0.7.0 | Classes\NoExtendsRule | 继承未允许的类时报错;0.7.1 起内置一组"默认允许被继承"的类 |
| 0.9.0 / 1.0.0 | FinalRule忽略 Doctrine 实体 | 先忽略注解式实体(@ORM\Mapping\Entity),1.0.0 起也忽略带Doctrine\ORM\Mapping\Entity属性的实体 |
| 0.15.0 | Classes\PHPUnit\Framework\TestCaseWithSuffixRule | 继承PHPUnit\Framework\TestCase的具体类必须以Test结尾 |
| 0.13.0 | Methods\PrivateInFinalClassRule | final类中的protected方法若可降级为private则报错;2.5.1 起忽略匿名类、trait 中继承来的protected方法,以及被 PHPUnit 属性/注解要求为protected的方法 |
| 0.12.0 | Methods\FinalInAbstractClassRule | abstract类中具体的public/protected方法必须final;0.15.1 起允许抽象类中存在非final的public构造函数 |
| 2.10.0 | Methods\InvokeParentHookMethodRule | 覆写父类 hook 方法时若未按预期顺序调用父类实现则报错,行为通过hookMethods参数定义 |
2. 参数与类型声明约束(Closures / Functions / Methods)
- 0.3.0 批量引入:
Functions\NoNullableReturnTypeDeclarationRule、Methods\NoNullableReturnTypeDeclarationRule、Closures\NoParameterWithNullDefaultValueRule、Closures\NoNullableReturnTypeDeclarationRule、Functions\NoParameterWithNullDefaultValueRule、Methods\NoParameterWithNullDefaultValueRule、Closures\NoParameterWithNullableTypeDeclarationRule、Functions\NoParameterWithNullableTypeDeclarationRule、Methods\NoParameterWithNullableTypeDeclarationRule。 - 0.5.0:新增
Methods\NoConstructorParameterWithDefaultValueRule,禁止类与匿名类的构造函数参数带默认值。 - 0.12.0:新增
Methods\NoParameterWithContainerTypeDeclarationRule,禁止方法参数类型声明为已知的依赖注入容器或服务定位器(默认Psr\Container\ContainerInterface,可通过interfacesImplementedByContainers扩展)。 - 2.0.0:新增
methodsAllowedToUseContainerTypeDeclarations参数,白名单内的方法名允许使用容器类型声明。 - 2.7.0:新增
Closures\NoParameterPassedByReferenceRule、Functions\NoParameterPassedByReferenceRule、Methods\NoParameterPassedByReferenceRule(禁止参数按引用传递)以及Functions\NoReturnByReferenceRule、Methods\NoReturnByReferenceRule(禁止按引用返回)。 - 2.5.2:上述 6 条 nullable 相关规则补强——能识别
null以错误大小写(如Null)或相对于根命名空间引用的情况。
3. 表达式与语句约束(Expressions / Statements / CallLikes)
- 0.11.0 批量引入:
Expressions\NoEmptyRule(empty())、Expressions\NoEvalRule(eval())、Expressions\NoErrorSuppressionRule(@错误抑制)、Expressions\NoCompactRule(compact())、Statements\NoSwitchRule(switch)。同时要求nikic/php-parser:^4.2.3、phpstan/phpstan:~0.11.15。 - 0.8.0:
Expressions\NoIssetRule(isset()),0.8.1 修复了该规则未被真正启用的问题。 - 2.8.0:新增
Expressions\NoAssignByReferenceRule,禁止变量按引用赋值。 - 2.9.0:新增
CallLikes\NoNamedArgumentRule,禁止以命名参数(named argument)调用匿名函数、函数或方法。 - 2.0.0:
Expressions\NoEmptyRule被移除(breaking change),empty()不再由本扩展约束。 - 2.10.4 / 2.10.5:
NoNamedArgumentRule持续修复——支持变量表达式上的静态调用、invokable 调用、属性上的 callable、变量类名构造函数;对无法解析的调用退化为通用错误消息,仅对已知调用给出精确描述。
4. 文件级约束(Files)
- 0.11.0:
Files\DeclareStrictTypesRule,PHP 文件缺少declare(strict_types=1)时报错;0.14.3 起忽略首行为 shebang 的情况。 - 2.13.0:
Files\NoPhpstanIgnoreRule,发现@phpstan-ignore、@phpstan-ignore-line、@phpstan-ignore-next-line标签时报错,强制"修掉错误或使用 baseline,而不是就地忽略"。
5. 错误消息与标识符演进
- 0.4.0:移除错误消息中的双引号、统一方法/函数/参数名的措辞与位置,使输出风格与 phpstan/phstan 自身错误消息一致。
- 2.5.0:为每条规则引入机器可读的错误标识符(error identifier);2.5.1 起规则通过 builder 正式返回带标识符的错误,2.6.1 修复
NoParameterWithNullableTypeDeclarationRule使用了不正确的标识符,2.10.2 为InvokeParentHookMethodRule重命名了标识符。
三、三个关键里程碑的深度解读
1. 0.14.0:命名空间迁移与参数段重构(breaking change)
这是 0.x 阶段最重要的破坏性版本,包含两项必须手工迁移的变更:
其一,vendor 命名空间从Localheinz更名为Ergebnis。官方给出的三步升级命令:
composer remove localheinz/phpstan-rules composer require ergebnis/phpstan-rules再替换源码与配置中出现过的Localheinz\PHPStan前缀:
find . -type f -exec sed -i '.bak' 's/Localheinz\\PHPStan/Ergebnis\\PHPStan/g' {} \;最后清理备份文件:
find -type f -name '*.bak' -delete其二,参数从全局parameters段移入ergebnis段。此前phpstan.neon的写法是:
parameters: allowAbstractClasses: true classesAllowedToBeExtended: [] classesNotRequiredToBeAbstractOrFinal: [] interfacesImplementedByContainers: - Psr\Container\ContainerInterface0.14.0 之后这些参数必须全部嵌套到ergebnis之下(防止与 PHPStan 全局参数命名冲突):
parameters: - allowAbstractClasses: true - classesAllowedToBeExtended: [] - classesNotRequiredToBeAbstractOrFinal: [] - interfacesImplementedByContainers: - - Psr\Container\ContainerInterface + ergebnis: + allowAbstractClasses: true + classesAllowedToBeExtended: [] + classesNotRequiredToBeAbstractOrFinal: [] + interfacesImplementedByContainers: + - Psr\Container\ContainerInterface同版本还修复了composer.json中不当的replace配置(0.14.1)、恢复了 PHP 7.1 支持(0.14.2)、并借 0.10.0 的parametersSchema保证了与bleedingEdge.neon的兼容性。
2. 1.0.0:正式稳定
1.0.0 起支持phpstan/phpstan:^1.0.0并放弃非稳定版本;同时FinalRule不再对带Doctrine\ORM\Mapping\Entity属性的非 final 类报错。此后0.x阶段结束,进入语义化版本承诺期。
3. 2.0.0:面向 PHPStan 2.x 的大版本
2.0.0 是一次集中的破坏性变更:
- 移除 PHP 7.2 / 7.3 / 7.4 支持,新增 PHP 8.2 支持;
- 新增
methodsAllowedToUseContainerTypeDeclarations参数(允许使用容器类型声明的方法名列表); - 新增"禁用任意规则"的能力(配合后文
enabled: false使用); - 支持 nullable union types;
- 移除
Expressions\NoEmptyRule。
此后的 2.x 演进主线是"扩平台 + 加规则":2.1.0 丢弃 PHP 8.0、支持 PHP 8.3;2.2.0 允许nikic/php-parser:^5.0.0;2.3.0/2.4.0 支持 PHP 8.4;2.5.0 支持 PHP 7.4 与 8.0 并移除对nikic/php-parser的依赖;2.6.0 支持phpstan/phpstan:^2.0.0;2.11.0/2.12.0 支持 PHP 8.5;2.14.0 允许安装于 PHP 8.6。依赖上,2.9.0 要求phpstan/phpstan:^2.1.8,2.13.0 提高到^2.1.35。
四、当前规则清单与完整配置参数(依据 rules.neon)
包内 rules.neon 是配置中枢:conditionalTags依据各规则的enabled参数决定是否注册为 PHPStan 规则;parameters给出全部默认值;parametersSchema定义参数结构校验;services完成依赖注入。
当前 2.14.0 共注册 25 条规则,全部默认启用(顶层ergebnis.allRules: true):
| 规则类 | 规则 | 关键参数(默认值) |
|---|---|---|
CallLikes\NoNamedArgumentRule | 禁止命名参数调用 | enabled |
Classes\FinalRule | 类必须 final | enabled、allowAbstractClasses(true)、classesNotRequiredToBeAbstractOrFinal([]) |
Classes\NoExtendsRule | 禁止继承未许可类 | enabled、classesAllowedToBeExtended([]) |
Classes\PHPUnit\Framework\TestCaseWithSuffixRule | 测试类须以 Test 结尾 | enabled |
Closures\NoNullableReturnTypeDeclarationRule | 闭包禁止可空返回类型 | enabled |
Closures\NoParameterPassedByReferenceRule | 闭包禁止按引用传参 | enabled |
Closures\NoParameterWithNullableTypeDeclarationRule | 闭包禁止可空参数类型 | enabled |
Expressions\NoAssignByReferenceRule | 禁止按引用赋值 | enabled |
Expressions\NoCompactRule | 禁止compact() | enabled |
Expressions\NoErrorSuppressionRule | 禁止@抑制错误 | enabled |
Expressions\NoEvalRule | 禁止eval() | enabled |
Expressions\NoIssetRule | 禁止isset() | enabled |
Files\DeclareStrictTypesRule | 必须declare(strict_types=1) | enabled |
Files\NoPhpstanIgnoreRule | 禁止@phpstan-ignore*标签 | enabled |
Functions\NoNullableReturnTypeDeclarationRule | 函数禁止可空返回类型 | enabled |
Functions\NoParameterPassedByReferenceRule | 函数禁止按引用传参 | enabled |
Functions\NoParameterWithNullableTypeDeclarationRule | 函数禁止可空参数类型 | enabled |
Functions\NoParameterWithNullDefaultValueRule | 函数参数禁止null默认值 | enabled |
Functions\NoReturnByReferenceRule | 禁止按引用返回 | enabled |
Methods\FinalInAbstractClassRule | 抽象类具体方法须 final | enabled |
Methods\InvokeParentHookMethodRule | hook 方法须按序调用父类实现 | enabled、hookMethods([]) |
Methods\NoConstructorParameterWithDefaultValueRule | 构造参数禁止默认值 | enabled |
Methods\NoNullableReturnTypeDeclarationRule | 方法禁止可空返回类型 | enabled |
Methods\NoParameterPassedByReferenceRule | 方法禁止按引用传参 | enabled |
Methods\NoParameterWithContainerTypeDeclarationRule | 方法禁止容器类型声明 | enabled、interfacesImplementedByContainers([Psr\Container\ContainerInterface])、methodsAllowedToUseContainerTypeDeclarations([]) |
Methods\NoParameterWithNullableTypeDeclarationRule | 方法禁止可空参数类型 | enabled |
Methods\NoParameterWithNullDefaultValueRule | 方法参数禁止null默认值 | enabled |
Methods\NoReturnByReferenceRule | 方法禁止按引用返回 | enabled |
Methods\PrivateInFinalClassRule | final 类中 protected 应降为 private | enabled |
Statements\NoSwitchRule | 禁止switch | enabled |
(其中Closures\NoParameterWithNullDefaultValueRule与Expressions\NoEmptyRule已不在当前清单中:前者未出现在rules.neon的 conditionalTags 内,后者在 2.0.0 被移除。)
invokeParentHookMethod.hookMethods的 schema 定义较为独特,每个元素包含四个字段(依据parametersSchema):
className(string):hook 方法所属父类名;methodName(string):hook 方法名;hasContent("no"或"yes"):父类实现是否有内容;invocation("any"、"first"或"last"):子类应在何时调用父类实现。
配置示例:按需启停规则
启用全部规则即可省略ergebnis段(默认allRules: true);只启用部分规则则把allRules设为false并逐个声明:
parameters: ergebnis: allRules: false final: enabled: true allowAbstractClasses: false classesNotRequiredToBeAbstractOrFinal: - PHPUnit\Framework\TestCase privateInFinalClass: enabled: true noExtends: enabled: true classesAllowedToBeExtended: - Symfony\Component\EventDispatcher\EventSubscriberInterface五、错误标识符体系
自 2.5.0 引入、2.5.1 起随错误正式返回的错误标识符(error identifier),统一形如ergebnis.<ruleName>。定义集中在 src/ErrorIdentifier.php:final()→ergebnis.final、noPhpstanIgnore()→ergebnis.noPhpstanIgnore、privateInFinalClass()→ergebnis.privateInFinalClass、noNamedArgument()→ergebnis.noNamedArgument等(toString()方法负责拼接前缀,见 src/ErrorIdentifier.php#L138-L144)。
标识符的价值在于:它允许在 PHPStan 的reportUnmatchedIgnoredErrors场景下精确匹配/忽略特定规则、在 CI 中按标识符聚合统计错误,也让@phpstan-ignore ergebnis.noCompact这类带标识符的定向忽略成为可能——当然,NoPhpstanIgnoreRule会禁止你这么做(详见下一节)。
六、源码剖析与在本仓库中的实际落地
NoPhpstanIgnoreRule 的实现方式
src/Files/NoPhpstanIgnoreRule.php 是 2.13.0 新增规则的代表性实现:它实现了PHPStan\Rules\Rule<FileNode>(getNodeType()返回FileNode::class,见 L29-L32),用PhpParser\NodeFinder遍历文件全部节点,收集每个节点的注释并按行匹配正则@phpstan-ignore(-line|-next-line)?(见 L49);一旦命中,就报出提示"应修复错误或改用 baseline,而不是用@phpstan-ignore就地忽略"(消息文本见 L55-L58),并通过ErrorIdentifier::noPhpstanIgnore()携带标识符、nonIgnorable()标记为不可忽略。2.13.1 修复了它遍历节点不全的问题,2.14.0 又修正了Functions\NoParameterPassedByReferenceRule的错误标识符。
php-file-iterator 中的真实配置
仓库根目录的 phpstan.neon 是这套扩展在真实项目中的配置范本:
parameters: level: 10 paths: - src - tests/unit strictRules: allRules: false booleansInConditions: true closureUsesThis: true disallowedBacktick: true disallowedEmpty: true disallowedImplicitArrayCreation: true disallowedLooseComparison: true disallowedShortTernary: true illegalConstructorMethodCall: true matchingInheritedMethodNames: true noVariableVariables: true numericOperandsInArithmeticOperators: true overwriteVariablesWithLoop: true requireParentConstructorCall: true strictFunctionCalls: true switchConditionsMatchingType: true uselessCast: true ergebnis: allRules: false final: enabled: true privateInFinalClass: enabled: true includes: - phar://phpstan.phar/conf/bleedingEdge.neon可见该项目的做法是:分析等级拉到level: 10并叠加bleedingEdge.neon(这正是 0.10.0 补上parametersSchema后得以兼容的场景),同时并行使用phpstan-strict-rules与ergebnis/phpstan-rules两套扩展;对ergebnis只显式启用final与privateInFinalClass两条最符合该库"类设计收敛"诉求的规则,其余规则保持关闭(allRules: false)。依赖侧,tools/.phpstan/composer.json 声明ergebnis/phpstan-rules: ^2.14.0、phpstan/phpstan: ^2.2.17、phpstan/extension-installer: ^1.4.3(后者自动激活rules.neon的 include),并由 composer.lock 锁定到 2.14.0。
七、升级与维护建议
- 版本策略:以 SemVer 为准。
2.x内部的小版本升级通常安全(新增规则默认启用可能带来新报错,建议升级后先跑一遍全量分析);3.0.0如出现,需重点核对规则移除与参数结构变更。 - 0.14.0 之前的老用户:参照第三节的迁移命令,完成命名空间替换与参数移入
ergebnis段两步操作。 - 新增规则默认全开:
allRules: true意味着每次升级都可能引入新的约束(如 2.13.0 的NoPhpstanIgnoreRule会立刻对既有@phpstan-ignore标签报错)。若担心波动,可先设allRules: false再逐个enabled: true灰度。 - 与 strict-rules 的取舍:
ergebnis/phpstan-rules偏"设计约束",phpstan/phpstan-strict-rules偏"严格语义",两者互补;php-file-iterator 的 phpstan.neon 就是两者同开的参考配置。
八、结语
从 0.1.0 的单一AbstractOrFinalRule到 2.14.0 的 25 条规则、错误标识符体系、allRules总开关与 PHP 8.6 支持,ergebnis/phpstan-rules的变更记录完整展现了"类设计收敛 → 类型声明纪律 → 表达式/语句禁令 → 文件级规范"这条规则谱系。对使用者而言,最有价值的不是背诵每条规则,而是掌握 rules.neon 这一配置中枢:用allRules控制总体范围、用各规则的enabled与专项参数微调边界、用错误标识符对接 CI 与 IDE。本文的版本对照表与配置示例可直接复制到你的phpstan.neon中按需裁剪。
- 开发工具
【免费下载链接】php-file-iterator
FilterIterator implementation that filters files based on a list of suffixes, prefixes, and other exclusion criteria.
相关推荐
从 0.1.0 到 2.14.0:ergebnis/phpstan-rules 演进全解析与 PHPStan 规则扩展实战指南
从 0.1.0 到 2.14.0:ergebnis/phpstan rules 演进全解析与 PHPStan 规则扩展实战指南 本文以 ergebnis/php
后端ergebnis/phpstan-rules 全版本解读:从 0.1.0 到 2.14.0 的规则演进与 PHPStan 配置实战
ergebnis/phpstan rules 全版本解读:从 0.1.0 到 2.14.0 的规则演进与 PHPStan 配置实战 导读 本文基于 php co
测试代码质量ergebnis/phpstan-rules 演进全解:从 0.1.0 到 2.14.0 的 PHPStan 规则库变更史与迁移指南
ergebnis/phpstan rules 演进全解:从 0.1.0 到 2.14.0 的 PHPStan 规则库变更史与迁移指南 这篇技术指南以 ergeb
开发工具测试
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考