十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PHPStan 错误标识符 `new.internalClass` 全解:禁止在包外实例化 `@internal` 类

PHPStan 错误标识符 `new.internalClass` 全解:禁止在包外实例化 `@internal` 类 开发工具代码质量静态分析【免费下载链接】phpstanPHP Static Analysis Tool - discover bugs in your code without running it!项目地址https://gitcode.com/gh_mirrors/ph/phpstan点击查看免费下载new.internalClass是 PHPStan 静态分析器在检测到代码从包package外部直接实例化一个被标记为internal的类时报告的错误标识符。本篇技术指南以 PHPStan 官方错误标识符文档 website/errors/new.internalClass.md 为主体结合仓库内 errorsIdentifiers.json 注册表、Restricted Usage Extensions 文档 与 PHPDoc 基础文档 中的实现证据讲解该错误的触发条件、底层产生机制、修复方法以及它在整个internalClass标识符家族中的位置帮助你准确理解并治理对内部 API 的越界使用。该错误标识符的官方定义该文档的 Frontmatter 元数据如下title: new.internalClass shortDescription: Instantiating a class marked as internal from outside its package. ignorable: truetitle错误标识符名称即new.internalClassshortDescription一句话描述触发场景——从包外部实例化一个被标记为internal的类ignorabletrue表示该错误属于可忽略错误允许通过ignoreErrors配置或phpstan-ignore注释将其加入忽略列表与通过-nonIgnorable()构建、不可忽略的规则相对可参考 website/errors/CLAUDE.md 中关于 Frontmatter 字段的说明。何时触发最小复现示例原文档给出了一个最小化的触发示例在Vendor命名空间定义被internal标记的类再从App命名空间即包外部直接new它?php declare(strict_types 1); namespace Vendor { /** internal */ class InternalHelper {} } namespace App { $helper new \Vendor\InternalHelper(); // error: Instantiation of internal class Vendor\InternalHelper. }触发条件可归纳为两点缺一不可被实例化的类声明了internalPHPDoc 标签实例化代码位于该类所属根命名空间root namespace之外。只要满足这两点PHPStan 就会报告Instantiation of internal class Vendor\InternalHelper.并使用标识符new.internalClass。为什么会报告internal的语义约定原文档从语言语义角度解释了报告原因被实例化的类标记为internal意味着它不属于该包的公共 API。内部类可能在任何版本中发生变化或被移除且不遵循语义化版本semantic versioning约定。从包外部使用它们会形成脆弱的依赖关系——在包更新时可能毫无预警地导致代码失效。从 PHPStan 的设计角度看internal的语义在 PHPDoc 基础文档 的 Internal symbols 一节中有明确界定该功能标注为Available in PHPStan 2.1.13 Bleeding Edgenamespace AwesomeLibrary\Foo; /** internal */ class Foo { }文档原文指出Usages of classFoooutside of topAwesomeLibrarynamespace will be reported as an error.——即在AwesomeLibrary顶级命名空间之外使用类Foo都会被报告为错误。因此判断是否越界的依据是根命名空间边界而非简单的同类/同包判断。同时文档强调internal标签不仅可用于类还可用于接口interfaces、枚举enums、trait、属性properties、方法methods、类常量class constants和函数functions。这也解释了为什么internalClass家族存在大量派生标识符见下文标识符家族一节。如何修复原文档给出的修复方向是使用包提供的公共 API 来替代直接实例化内部类namespace App { - $helper new \Vendor\InternalHelper(); $helper \Vendor\HelperFactory::create(); }如果包不存在任何公共替代方案原文档建议向包维护者提交功能请求feature request请求将所需能力以公共 API 的形式暴露出来。从工程实践角度还可以补充以下处理思路优先寻找官方入口大多数将实现类标为internal的库都会同时提供工厂方法、服务定位器、门面facade或依赖注入容器来创建实例应优先使用这些入口确认是否真的需要越界使用internal往往意味着该实现细节在后续版本中可能被重构直接实例化会让升级成本成倍增加仅在确认无公共 API 且短期无法替代时才考虑通过ignoreErrors配置或phpstan-ignore注释将特定位置加入忽略列表由于ignorable: truePHPStan 允许这样做但应对此类豁免进行审查与跟踪。源码级原理new.internalClass是如何产生的new.internalClass并非一个独立编写的规则而是由 PHPStan 2.1.13 引入的Restricted Usage受限使用扩展机制统一生成的。相关证据记录在仓库的 errorsIdentifiers.jsonL11773-L11779中new.internalClass: { PHPStan\\Rules\\InternalTag\\RestrictedInternalClassNameUsageExtension: { phpstan/phpstan-src: [ https://github.com/phpstan/phpstan-src/blob/2.3.x/src/Rules/InternalTag/RestrictedInternalClassNameUsageExtension.php#L65 ] } }即该标识符由规则类PHPStan\Rules\InternalTag\RestrictedInternalClassNameUsageExtension产生该类实现位于上游phpstan-src仓库的src/Rules/InternalTag/RestrictedInternalClassNameUsageExtension.php当前仓库为文档镜像仅保存注册表记录。生成链路ClassNameUsageLocation 与消息/标识符模板Restricted Usage Extensions 文档 揭示了完整的生成链路该文档标注Available in PHPStan 2.1.13RestrictedClassNameUsageExtension扩展接口会被调用在超过 25 种类名引用位置上——包括class extends、class implements、参数/返回类型声明、PHPDoc 引用、静态方法调用Foo::doBar()、静态属性与类常量访问以及new ClassName()实例化扩展通过ClassNameUsageLocation对象携带使用位置信息从而区分同一类名出现在不同语法位置时各自的标识符当类被标记为internal时扩展会以internal class Foo作为消息模板、internalClass作为标识符模板交给ClassNameUsageLocation的createMessage()/createIdentifier()方法组合出最终消息与标识符。原文档给出了组合后的对应关系PHPDoc tag property references internal class Foo./propertyTag.internalClassInstantiation of internal class Foo./new.internalClassClass Bar implements internal class Foo./class.implementsInternalClass可以看到new.internalClass正是new实例化位置与internalClass受限类类型两个维度的组合结果——这与 website/errors/CLAUDE.md 中Identifier prefix reference表格对new前缀的界定对应new ClassName()实例化完全一致。与 InstantiationRule 的关系值得注意的对比是new.interface、new.notFound等new.*前缀标识符来自PHPStan\Rules\Classes\InstantiationRule见 errorsIdentifiers.json L11760-L11772 附近而new.internalClass则来自 Restricted Usage 机制。这说明 PHPStan 对new表达式的分析是分层的InstantiationRule负责实例化本身的结构性检查如实例化接口、实例化不存在的类Restricted Usage 扩展体系负责类名在何处被使用的位置敏感检查如是否越界使用内部类。两者互补共同构成了对new ClassName()的完整静态分析。标识符家族new.internalClass在 internalClass 系列中的位置internal标签可作用于多种声明因此internalClass作为标识符模板可以组合出庞大的家族。当前仓库 website/errors 目录下已收录的同类文档包括仅列部分method.internalClass调用属于internal类的方法对应文档 method.internalClass.md 的示例——对\Vendor\Service内部类实例调用$service-process()classConstant.internalClass访问内部类的类常量property.internalClass/propertyTag.internalClass访问内部类属性 / 在propertyPHPDoc 中引用内部类attribute.internalClass将内部类用作 PHP 8.0 属性Attributecatch.internalClass在catch块中捕获内部类instanceof.internalClass对内部类使用instanceofmixin.internalClass在mixinPHPDoc 中引用内部类assert.internalClass在phpstan-assertPHPDoc 中引用内部类generics.internalClassBound/generics.internalClassDefault在template T of 内部类泛型约束或默认值中引用以及class.extendsInternalClass、class.implementsInternalClass、enum.implementsInternalClass等特殊格式的派生标识符同一段越界使用内部类的代码只要使用位置不同就会被报告为不同的标识符。这种细粒度设计使得团队可以按使用位置分别配置 ignoreErrors、分别做基线管理而不必一刀切地忽略全部内部类违规。适用前提与启用方式根据 PHPDoc 基础文档Internal symbols 一节的标注内部符号检测功能需要PHPStan 2.1.13 及以上版本该功能属于Bleeding Edge试验性功能需要显式启用在配置文件中加入includes: [phar://phpstan.phar/conf/bleedingEdge.neon]对应仓库根目录的 conf/bleedingEdge.neon。只有在满足上述前提的情况下new.internalClass才会被报告在旧版本或未启用 Bleeding Edge 时internal类仍可被自由实例化而不会触发该错误。总结new.internalClass是 PHPStan Restricted Usage 机制针对包外实例化internal类这一具体场景派生的错误标识符。理解它的关键在于三件事触发条件被实例化的类声明了internal且实例化代码位于该类根命名空间之外产生机制它由RestrictedInternalClassNameUsageExtension通过ClassNameUsageLocation的位置感知模板newinternalClass生成与InstantiationRule的结构性检查相互补充修复策略优先切换到包的公共 API工厂、门面、DI 容器等没有公共替代方案时向维护者请求新增公共入口而不是直接把internal当摆设。通过正确治理内部类越界使用可以让你的项目对上游包的升级保持稳健避免在依赖更新时遭遇毫无预警的破坏。延伸阅读仓库内相关资源错误标识符文档生成规范了解每个website/errors/*.md文件的结构、Frontmatter 字段与标识符前缀约定Restricted Usage Extensions 文档RestrictedClassNameUsageExtension接口定义、注册方式phpstan.restrictedClassNameUsageExtension标签与消息/标识符模板组合逻辑PHPDoc 基础文档 - Internal symbolsinternal标签的适用范围与命名空间边界规则错误标识符注册表new.internalClass到规则类的映射记录赞分享开发工具代码质量静态分析【免费下载链接】phpstanPHP Static Analysis Tool - discover bugs in your code without running it!项目地址https://gitcode.com/gh_mirrors/ph/phpstan点击查看免费下载相关推荐PHPStan 错误标识符 new.internalInterface 完全解读禁止实例化 internal 内部接口PHPStan 错误标识符 new.internalInterface 完全解读禁止实例化 internal 内部接口 本篇技术指南围绕 PHPStan 错开发工具代码质量静态分析PHPStan 错误标识符详解classConstant.internal —— 类常量 internal 访问违例检测PHPStan 错误标识符详解classConstant.internal —— 类常量 internal 访问违例检测 导读 本文围绕 PHPStan 错开发工具代码质量静态分析终极实战指南用Redis Exporter构建企业级Redis监控体系终极实战指南用Redis Exporter构建企业级Redis监控体系 在当今数据驱动的应用架构中Redis作为高性能内存数据库已成为关键基础设施组件。然而开发工具代码质量静态分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表