多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

PHPStan 错误标识符 new.void 深度解析:new 表达式结果被用作 void 的静态分析报告

PHPStan 错误标识符 new.void 深度解析:new 表达式结果被用作 void 的静态分析报告 开发工具代码质量静态分析【免费下载链接】phpstanPHP Static Analysis Tool - discover bugs in your code without running it!项目地址https://gitcode.com/gh_mirrors/ph/phpstan点击查看免费下载导读new.void是 PHPStanPHP 静态分析工具可在不运行代码的情况下发现代码中的 bug众多错误标识符error identifier之一用于标记「new表达式的结果被用在一个计算结果为 void 的上下文中」这类可疑代码。本文以 new.void.md 为骨架结合 errorsIdentifiers.json 中的源码映射、CLAUDE.md 中的文档规范与 errorIdentifierGroups.js 中的标识符分组逻辑完整讲解该标识符的触发示例、报告原因、修复方式以及它在 PHPStan 错误标识符体系中的位置与特殊标记feasible: false的真实含义。读完本文你将能识别这类「把本不应产生值的表达式当值使用」的代码隐患并掌握 PHPStan 错误标识符文档的阅读与验证方法。一、new.void 是什么new.void是 PHPStan 规则系统输出的一个错误标识符。在 PHPStan 2.x 的架构中每一条规则报告的错误都可以携带一个稳定的字符串标识符方便开发者用ignoreErrors精确配置忽略、在 CI 中过滤或在 website/errors 目录下查阅对应的官方解释文档。根据 new.void.md 的 frontmattertitlenew.void即错误标识符本体shortDescriptionResult of a new expression is used in a context where it evaluates to void.一个new表达式的结果被用在一个计算结果为 void 的上下文中ignorabletrue表示该错误允许通过ignoreErrors配置忽略feasiblefalse这是一个值得注意的特殊标记本文第五节会专门说明。前缀new的含义在 CLAUDE.md 的「Identifier prefix reference」表中被明确解释new前缀对应 PHP 的new ClassName()实例化表达式。因此new.void属于「与对象实例化相关」的错误家族同族标识符还包括new.abstract实例化抽象类、new.interface实例化接口、new.trait实例化 trait、new.resultUnused独立成行的实例化结果未被使用、new.nonObject对非类表达式使用 new等。二、触发示例官方文档中的代码new.void.md 给出的最小触发示例是一个带有构造方法的Logger类以及一个创建其实例并在函数中使用的getLogger()?php declare(strict_types 1); class Logger { public function __construct() { } } function getLogger(): Logger { $result new Logger(); echo $result; return $result; }这个示例体现了文档的通用写作规范以?php declare(strict_types 1);开头使用最小化的类名将问题聚焦在单个构造调用上。需要注意的是示例中echo $result;本身也可能触发「object 无法转换为 string」类别的报告官方文档将其作为展示new表达式结果被「消费」的一个典型上下文。三、为什么会被报告根据 new.void.md 的「Why is it reported?」章节该错误的本质是一个new表达式的结果被用在了计算结果为 void 的上下文中。这通常发生在 PHPStan 判定当前上下文中的构造调用会产生 void 结果时例如new表达式被用在 attribute属性PHP 8.0声明内部或其他「返回值没有意义」的特殊上下文里。从 PHP 语言语义的角度看new ClassName()表达式的值应该是新创建的对象实例。但在 PHPStan 的类型推导体系中如果该表达式所在的上下文是 void 语义的比如构造参数校验、attribute 实参求值等只关心「执行」不关心「结果」的场景那么「把对象实例当结果使用」就是一种逻辑上的不自洽——它暗示开发者对返回值有期待而这个期待在当前上下文中无法被满足。这类报告的价值在于提示「开发者意图与代码实际行为不符」要么是开发者误以为能得到某个值而实际上得不到要么是代码在重构后残留了无意义的取值逻辑。它和同族的new.resultUnusednew.resultUnused.md独立成行的实例化结果未被使用一样都属于「构造调用结果的使用方式有问题」这一大类只是new.void更强调「结果被用在 void 上下文」。四、如何修复new.void.md 给出的修复建议非常直接当某个new表达式不应产生值、却把它的结果当值使用时就不要再把结果当作值使用。如果确实需要这个对象先把它赋值给一个变量再在后续语句中单独使用它。官方修复示例?php declare(strict_types 1); -echo new Logger(); $logger new Logger();修复要点可以归纳为两条实践准则按需创建、按需使用先把new的结果赋给局部变量如$logger new Logger();再在需要的地方引用$logger避免在一个不求值的上下文中直接消费实例表达式检查上下文语义如果new出现在 attribute 声明、void 返回值上下文等「结果无意义」的位置应确认这里是否需要实例化或者是否应该调整调用方式。同时可参考姊妹篇 attribute.void.md「void 返回的调用结果被用在 attribute 上下文中」与 callable.void.md、function.void.md、method.void.md、staticMethod.void.md 等系列文档凡是「void 结果被消费」的模式修复思路都是一致的——不要把不求值的表达式结果当作值来用。五、feasible: false 标记的真实含义这是阅读 new.void.md 时最容易忽略、却最有信息量的一个细节frontmatter 中的feasible: false。结合仓库中的处理逻辑可以看出它的作用errorIdentifiers.js 在加载错误文档时读取file.data.feasible ! false来判定该标识符是否「可行」feasibleerrorIdentifierGroups.js 中当文档的feasible false时会被标记为不可行并在分组统计中跳过if (!feasible || unlikely)直接 continue也就是说这类标识符不会出现在错误标识符的常规分组列表中errorIdentifierDetail.njk 在详情页渲染时也会针对feasible false做特殊处理向读者提示「该标识符不太可能在实际代码中被触发」。feasible: false的官方语义是虽然存在这个标识符及其文档但按当前 PHPStan 的规则实现实际很难甚至无法构造出真实触发它的代码场景。这一点也解释了为什么 new.void.md 中的代码示例更像「示意」而非「可复现的最小样例」——它演示的是概念层面的错误模式而非一个必然触发该标识符的 fixture。因此当你在自己的项目里几乎不会遇到new.void报告时请不要感到意外这是设计使然。六、源码层面的映射与验证在 errorsIdentifiers.json 中new.void标识符被映射到 phpstan-src 仓库的 FunctionCallParametersCheck.php第 318 行附近并由多个规则类共同关联PHPStan\Rules\Classes\ClassAttributesRule——类 attribute 检查PHPStan\Rules\Classes\InstantiationRule——实例化检查PHPStan\Rules\Functions\CallCallablesRule、CallToFunctionParametersRule、CallUserFuncRule——函数/可调用对象调用检查PHPStan\Rules\Methods\CallMethodsRule、CallStaticMethodsRule——方法与静态方法调用检查以及ClassConstantAttributesRule、ConstantAttributesRule、EnumCaseAttributesRule、ArrowFunctionAttributesRule、ClosureAttributesRule、FunctionAttributesRule、ParamAttributesRule、MethodAttributesRule、PropertyAttributesRule、PropertyHookAttributesRule、TraitAttributesRule等大量 attribute 相关规则。从源码结构可以看出两点关键事实该标识符的产生路径高度集中在「构造调用参数/结果校验」这一公共检查点无论调用形式是new、函数调用、方法调用、可调用对象还是 attribute 实参求值只要涉及「结果类型为 void 却被当作值」最终都会汇聚到FunctionCallParametersCheck的同一段逻辑第 318 行这解释了为什么new.void会同时挂在一长串规则类名下attribute 上下文是其重要触发场景映射列表中出现了大量*AttributesRule印证了文档「例如用在 attribute 声明内部」的描述——attribute 实参在 PHP 中本身不产生有意义的运行时返回值PHPStan 在此类上下文中对「结果被使用」的判定尤为严格。需要说明的是本仓库phpstan 镜像仓库本身不直接包含FunctionCallParametersCheck.php的实现源码上述映射信息来自 errorsIdentifiers.json 这一官方生成的标识符→源码位置索引可据此进一步深入 phpstan-src 源码验证具体逻辑。七、在错误标识符文档体系中的定位new.void文档是 website/errors 目录下数百个错误标识符文档之一。根据 CLAUDE.md 的说明这些文档由 CI 工作流基于errorsIdentifiers.json生成遵循统一的 frontmatter 「Code example / Why is it reported? / How to fix it」三段式结构Code example必须是从测试 fixture 中提炼的最小合法 PHP 代码Why is it reported?从 PHP 语言语义而非 PHPStan 内部实现的角度解释How to fix it按「先修 bug、再用原生类型声明收窄、再用 PHPDoc 收窄、再类型收窄、最后配置 PHPStan」的优先级给出修复方案代码改动用diff-php语法展示。new.void文档完全遵循这一模板同时以feasible: false标注了其「示例场景」属性使读者在查阅时能正确区分「真实可触发的错误」与「概念性的错误模式」。如果你在自己的项目中确实收到了new.void报告例如在 attribute 实参中直接消费new表达式可以依据上文第四节的方式修复如果只是想了解 PHPStan 如何处理「void 结果被消费」这一类问题则可以顺着function.void、method.void、callable.void、attribute.void、new.resultUnused等系列文档系统性地阅读形成完整认知。赞分享开发工具代码质量静态分析【免费下载链接】phpstanPHP Static Analysis Tool - discover bugs in your code without running it!项目地址https://gitcode.com/gh_mirrors/ph/phpstan点击查看免费下载相关推荐PHPStan 错误标识符 match.voidmatch 表达式结果全为 void 时的检测与修复PHPStan 错误标识符 match.voidmatch 表达式结果全为 void 时的检测与修复 导读 本文聚焦 PHPStan 的错误标识符 match开发工具代码质量静态分析PHPStan 错误标识符深度解析booleanAnd.resultUnused 运算结果未使用PHPStan 错误标识符深度解析booleanAnd.resultUnused 运算结果未使用 booleanAnd.resultUnused 是开发工具代码质量静态分析PHPStan 错误标识符 booleanOr.resultUnused 深度解析|| 运算结果未被使用的检测与修复PHPStan 错误标识符 booleanOr.resultUnused 深度解析 || 运算结果未被使用的检测与修复 booleanOr.resultUnu开发工具代码质量静态分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表