PHPStan 错误标识符文档体系全解析从 Rule 源码到自动生成文档的工程实践【免费下载链接】phpstanPHP Static Analysis Tool - discover bugs in your code without running it!项目地址: https://gitcode.com/gh_mirrors/ph/phpstanPHPStan 在报告每个错误时都会附带一个稳定且可机器识别的错误标识符Error Identifier如property.notFound、deadCode.unreachable而 website/errors/CLAUDE.md 正是这套标识符文档体系的核心规范文件。它规定了 phpstan.org 上每个错误详情页的生成方式、Markdown 文件格式、写作规则与标识符前缀语义。读完本文你将完整掌握 PHPStan 错误标识符文档的结构化格式、自动化生成流水线、全部标识符前缀的含义以及如何通过源码追溯一个标识符从 Rule 规则到文档的完整生命周期。一、这套文档体系是什么website/errors/目录存放的是 PHPStan 错误标识符的 Markdown 文档每个文件对应一个标识符例如 website/errors/deadCode.unreachable.md、website/errors/property.notFound.md。每个文件负责回答三个问题这个错误具体是什么意思什么代码会触发它附最小复现代码有哪些修复方式。这不仅是给开发者查阅的静态文档也是一套被 AIClaude自动化维护的活文档每当 PHPStan 新增或调整标识符工作流会自动为尚无文档的标识符补齐说明保证 phpstan.org 的错误标识符页面 永远不缺页。二、文档如何被自动生成根据 website/errors/CLAUDE.md这些文件由一个 GitHub Actions 工作流.github/workflows/generate-error-docs.md驱动使用 Claude 按以下步骤生成读取 website/src/errorsIdentifiers.json——该文件把每个标识符映射到其对应的 Rule 类与源码位置该文件在仓库中超过 1.8 万行例如argument.bitmaskNotAllowed同时映射到ClassAttributesRule、InstantiationRule、CallMethodsRule等十余个 Rule 类挑选出尚未被文档覆盖的标识符即在website/errors/下没有对应.md文件的标识符克隆相关的 PHPStan 仓库phpstan-src、phpstan-strict-rules、phpstan-doctrine等覆盖核心规则与生态扩展规则逐个研读 Rule 源码与测试夹具test fixtures理解错误触发条件为每个标识符生成一份 Markdown 文档。这套流程的触发端在仓库中同样可见.github/workflows/claude-update-error-docs-identifiers-change.yml 监听2.3.x分支上website/src/errorsIdentifiers.json的变化一旦标识符映射表更新就通过gh workflow run触发下游的文档更新任务。三、文档文件的标准格式每个错误文档文件遵循完全一致的模板结构--- title: identifier shortDescription: One sentence describing when this error is reported. ignorable: true --- ## Code example php ?php declare(strict_types 1); // Minimal PHP code that triggers this errorWhy is it reported?Explanation from PHP language perspective.How to fix itWays to fix the error.### Frontmatter 字段 | 字段 | 含义与取值规则 | |------|---------------| | title | 错误标识符本身例如 property.notFound | | shortDescription | 一句话以句号结尾从用户视角描述什么代码模式会导致 PHPStan 报告此错误。示例Accessing a private property from outside the declaring class.、Loose comparison using will always evaluate to true.、Pure function uses print, which produces output as a side effect. | | ignorable | 绝大多数标识符为 true对使用了 -nonIgnorable() 的规则链或以 phpstan.、phpstanPlayground. 开头的标识符必须设为 false | ignorable: false 的判断依据来自规则构造链中的 -nonIgnorable() 调用这类错误不允许用户通过 phpstan-ignore 或配置文件忽略因此详情页也不会提供忽略此错误的引导。 ### Code example 部分 - 必须是能真实触发该标识符的合法 PHP 代码 - 必须以 ?php declare(strict_types 1); 开头 - 使用 php 语言标签 - 保持最小化——移除无关类、简化命名 - 优先直接采用测试夹具test fixtures中的真实代码保证示例与 Rule 测试行为一致。 ### Why is it reported? 部分 - 从 **PHP 语言语义** 角度解释而非讲解 PHPStan 内部实现 - 核心判据PHPStan 指向的是会导致崩溃、根本不会执行、或与开发者意图不符的代码 - 有多个原因时逐条列出 - 若规则的 -tip() 链接到 phpstan.org 上的博客文章需注明 Learn more: Blog post title。 ### How to fix it 部分 修复建议遵循固定的优先级顺序 1. 修复真正的 bug 2. 使用原生 PHP 类型声明收窄类型 3. 使用 PHPDoc 类型收窄param、return、属性上的 var 4. 在函数体内使用类型收窄type narrowing技巧 5. 若该规则可配置则配置 PHPStan。 代码改动一律使用 diff-php 语法展示 markdown diff-php - $value $this-getValue(); $value (string) $this-getValue();此外规范还明确要求 - 当错误涉及仅在较新 PHP 版本可用的语言特性时必须同时给出在旧版本可用的 PHPDoc 替代写法——例如原生返回类型 neverPHP 8.1可用 return never 替代原生联合类型PHP 8.0可写成 PHPDoc 联合类型原生交叉类型PHP 8.1可写成 PHPDoc 交叉类型true/false/null 这类独立类型PHP 8.2也可写在 PHPDoc 中 - 每次提到配置参数都必须链接到正确的配置文档锚点依据 [website/src/config-reference.md](https://link.gitcode.com/i/46c48ca532ae9537ba8d02211eb0c80b) 判断拥有独立 ### 标题的参数如 phpVersion链接到 /config-reference#phpversion只出现在 Related config keys 中的参数则链接到对应用户指南页面如 reportUnmatchedIgnoredErrors 链接到忽略错误章节scanFiles 链接到符号发现章节。 ### Do NOT 清单 编写文档时严格禁止 - 建议使用 assert() 做类型收窄 - 建议抛出异常来收窄类型 - 建议使用行内 var PHPDoc 标签 - 建议直接忽略错误详情页本身已覆盖忽略方式 - 使用 emoji 或第一人称。 ## 四、标识符前缀参考表 标识符的命名不是随意的一部分前缀语义并不直观因为它们源自 PHPStan 内部枚举 ClassNameUsageLocation。规范文件中给出了完整对照 | Prefix | PHP Feature | |--------|-------------| | assert | phpstan-assert PHPDoc 标签注意**不是** assert() 函数 | | attribute | PHP 8.0 属性 #[AttributeName] | | catch | catch (ExceptionClass $e) 块 | | classConstant | ClassName::CONSTANT 访问 | | instanceof | $x instanceof ClassName 表达式 | | methodTag | method PHPDoc 标签 | | mixin | mixin PHPDoc 标签 | | new | new ClassName() 实例化 | | parameter | 函数/方法参数上的原生类型声明 | | property | 类属性上的原生类型声明如 private Foo $bar | | propertyTag | property PHPDoc 标签 | | requireExtends | phpstan-require-extends PHPDoc 标签 | | requireImplements | phpstan-require-implements PHPDoc 标签 | | return | 原生返回类型声明 | | sealed | phpstan-sealed PHPDoc 标签 | | selfOut | phpstan-self-out PHPDoc 标签 | | staticMethod | ClassName::method() 静态方法调用 | | staticProperty | ClassName::$property 静态属性访问 | | traitUse | 类体中的 use TraitName | | typeAlias | PHPStan 类型别名引用 | | varTag | var PHPDoc 标签 | ### 特殊格式的标识符前缀 除上述前缀外还有一类由前缀 通配符构成的组合模式 | Prefix pattern | PHP Feature | |----------------|-------------| | class.extends* | class Foo extends ParentClass | | class.implements* | class Foo implements Interface | | enum.implements* | enum Foo implements Interface | | interface.extends* | interface Foo extends OtherInterface | | generics.*Bound | template T of BoundClass 约束边界 | | generics.*Default | template T DefaultClass 默认值 | 这类模式解释了仓库中大量文档文件名的由来例如 [website/errors/class.extendsDeprecatedClass.md](https://link.gitcode.com/i/a7ce37388f43851adbde1711ace89d5c)、[website/errors/generics.notSubtype.md](https://link.gitcode.com/i/7256fdbea2c22a724fa5e1aa437dd706) 等。 ## 五、语气与风格要求 - 简洁、技术精确、无废话 - 与 phpstan.org 现有文档风格保持一致 - 直接、务实 - 对扩展专属标识符phpstan-doctrine、phpstan-symfony 等必须注明提供该规则的扩展包名称——例如 [website/errors/doctrine.dql.md](https://link.gitcode.com/i/8e4705ec2618d75adc20f5edd705dde0) 这类文档会明确指向 Doctrine 扩展。 ## 六、完整示例deadCode.unreachable 规范文件给出了 deadCode.unreachable 的完整参考文档即 [website/errors/deadCode.unreachable.md](https://link.gitcode.com/i/97fa1ae964f0d785c7347ab87562e4a1) 的真实内容 markdown --- title: deadCode.unreachable shortDescription: Code after a return or throw statement can never be executed. ignorable: true --- ## Code example php ?php declare(strict_types 1); function doFoo(): int { return 1; echo unreachable; } ## Why is it reported? The statement after return can never be executed. The return statement unconditionally transfers control out of the function, making any code following it in the same block dead code. This usually indicates a logic error or leftover code from refactoring. The same applies to other control flow statements that always terminate, such as throw, exit, continue, or break. ## How to fix it Remove the unreachable code: diff-php function doFoo(): int { return 1; - echo unreachable; } If the code should execute, restructure the logic so it runs before the return: diff-php function doFoo(): int { echo this should run; return 1; - echo unreachable; } 这个示例完整体现了规范的全部要点最小化触发代码、从 PHP 语言语义而非 PHPStan 内部机制解释原因、给出多种修复路径、修复展示使用 diff-php 语法、frontmatter 字段齐全。 ## 七、从源码追溯标识符的诞生 标识符文档的质量最终取决于标识符数据的准确性。仓库中的 identifier-extractor/ 目录就是负责从 PHPStan 源码中提取标识符与 Rule 类映射关系的独立工具它直接产出 [website/src/errorsIdentifiers.json](https://link.gitcode.com/i/39e1db4d78b9b0c5cdc7821ded8aad06) 这份驱动文档生成的清单。 其核心机制是两组 Collector基于 PHPStan 自身的分析器 - [identifier-extractor/src/ErrorWithIdentifierCollector.php](https://link.gitcode.com/i/2a5f396bfbfec0c915e1b1d52b1ae2f2)遍历所有 MethodCall 节点匹配名为 withIdentifier 的方法调用通过 $scope-getType($args[0]-value) 解析出作为常量字符串传入的标识符值并记录调用该方法的 Rule 类名、文件与行号 - [identifier-extractor/src/RuleErrorBuilderCollector.php](https://link.gitcode.com/i/b215614b5cfa3000223a0fca7ca645c9)对称地匹配 RuleErrorBuilder 上的 identifier() 方法调用同样解析标识符字符串并记录归属类。 数据输出由 [identifier-extractor/src/ErrorFormatter.php](https://link.gitcode.com/i/9a4fc5d1d56ce98eb9f2688e0a29a969) 完成它作为 PHPStan 的自定义 ErrorFormatter将收集到的 {identifiers, class, file, line} 组装为 JSON顶层还包含 repo 与 branch 环境变量从而把哪个 Rule 在哪个文件哪一行注册了哪个标识符结构化落盘。由此可以看出**errorsIdentifiers.json 不是手工维护的而是从 phpstan-src 及各扩展仓库源码中静态分析提取的产物**这保证了标识符文档与真实规则行为始终一一对应。 ## 八、这套体系对开发者的实用价值 - **使用 PHPStan 的开发者**理解了标识符前缀表就能从错误消息中的 identifier 一眼判断错误来自原生类型声明、PHPDoc 标签还是 PHP 语言特性如 attribute、enum、mixin从而更精准地定位问题 - **扩展Extension作者**通过 -identifier(myExtension.someError) 注册自定义标识符后可以参照 [website/errors/CLAUDE.md](https://link.gitcode.com/i/521b8ff0be4ad5672d8c186363587ad5) 的格式为自己的规则补齐文档同时也能理解 ignorable 字段与 -nonIgnorable() 的关系决定哪些错误允许用户忽略 - **文档贡献者**只要遵循 frontmatter 三段式结构、diff-php 修复示例、前缀表语义和 Do NOT 清单就能与官方自动化工作流产出的文档保持完全一致的风格保证整套错误文档体系的长期可维护性。 从 Rule 源码中的一行 -identifier(...)到提取器静态分析落盘 JSON再到 Claude 按规范生成 Markdown 详情页——这套以 [website/errors/CLAUDE.md](https://link.gitcode.com/i/521b8ff0be4ad5672d8c186363587ad5) 为中枢的流水线构成了 PHPStan 文档生态中一个完整、可复用的自动化工程范例。【免费下载链接】phpstanPHP Static Analysis Tool - discover bugs in your code without running it!项目地址: https://gitcode.com/gh_mirrors/ph/phpstan创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
迅雷会员账号共享机制揭秘: 3个核心代码片段一文搞懂底层逻辑 迅雷会员账号共享机制揭秘: 3个核心代码片段一文搞懂底层逻辑 面试被问“迅雷会员是怎么实现的?”答不上来?别慌,今天带你 一文搞懂 【迅雷会员账号共享】背后的源码逻辑。很多资深开发都在这个细节上栽过跟头,以为只是简单的 Token… · 2026/9/23 11:16:19
蛋白粉营养头部公司的核心竞争力与产业发展探析 一、蛋白粉营养赛道与头部公司核心特质伴随国民健康认知升级,蛋白质膳食补充需求持续释放,蛋白粉作为蛋白营养赛道核心产品,应用场景从专业健身拓展至产后营养、中老年膳食补充、日常体质管理等多元领域。蛋白粉依托乳清蛋白、酪蛋白、植物蛋… · 2026/9/23 11:16:13
OpenRLHF 多节点训练实战:基于 Ray 集群的跨机分布式 RLHF 完整指南 OpenRLHF 多节点训练实战:基于 Ray 集群的跨机分布式 RLHF 完整指南 【免费下载链接】AI-Research-SKILLs Comprehensive open-source library of AI research and engineering skills for any AI model. Package the skills and your claude code/codex/gemini age… · 2026/9/23 11:47:04
5个高频面试题讲透幻灯片备注原理,告别代码跑不通 5个高频面试题讲透幻灯片备注原理,告别代码跑不通 刚入职第一周,我拿着网上抄来的 PPT 自动化脚本去跑,结果报错 AttributeError: 'NotesSlide' object has no attribute 'text'… · 2026/9/23 11:46:51
3个致命坑让你发言变灾难一文搞懂开会发言技巧 3个致命坑让你发言变灾难一文搞懂开会发言技巧 刚进项目组那会儿,我最怕的就是周会。不是怕工作多,是怕开口。手里攥着PPT,手心全是汗,心里默念着“配置环境就卡半天”这种只有程序员才懂的焦虑,结果一上台,脑子直接死机。… · 2026/9/23 11:46:51
3步搭好国标行业项目,新手避坑指南 3步搭好国标行业项目,新手避坑指南 很多刚入行公路工程的朋友,对着《公路工程预算标准》里的代码头大。语法背得滚瓜烂熟,真上手搭项目却卡壳:数据怎么对齐?单位怎么换算?这就是典型的 新手避坑… · 2026/9/23 11:46:45
告别StackTrace报错,一文搞懂smv实战项目搭建 告别StackTrace报错,一文搞懂smv实战项目搭建 盯着屏幕上一堆红色的 StackTrace,你心里是不是在打鼓?明明只是跑个脚本,怎么就崩了?报错信息长得像天书,根本不知道从哪一行开始查。这种“报错一堆看不懂… · 2026/9/23 11:46:45
3步吃透延迟选择实验:从原理到代码的入门到精通 3步吃透延迟选择实验:从原理到代码的入门到精通 面试时被问“什么是延迟选择实验”,你脑子是不是瞬间一片空白?只记得薛定谔的猫,却讲不清双缝干涉背后的量子擦除逻辑?别慌,这种“知其然不知其然”的状态,正是从入门到精通的最大拦路虎。… · 2026/9/23 11:46:38
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29