- 开发工具
- 代码质量
- 静态分析
【免费下载链接】phpstan
PHP Static Analysis Tool - discover bugs in your code without running it!
本文围绕 PHPStan 官方错误标识符文档 property.readOnlyNoNativeType.md 展开,深入讲解readonly属性必须携带原生类型(native type)声明的语言级约束、该错误的触发场景与修复方案,并结合本仓库中的标识符映射表与配置参考,帮助读者在 PHP 8.1+ 项目中一次到位地消除此类问题。
读完本文,你将理解为什么 PHPDoc 类型无法替代原生类型、如何为 readonly 属性正确补齐string/ 联合类型 /mixed,以及如何通过phpVersion配置与错误忽略机制管理该标识符。
标识符速览:一条错误的全貌
在 website/errors/property.readOnlyNoNativeType.md 的 YAML frontmatter 中,该错误标识符的元信息如下:
| 字段 | 值 |
|---|---|
title | property.readOnlyNoNativeType |
shortDescription | Readonly property is missing a required native type declaration.(readonly 属性缺少必需的原生类型声明) |
ignorable | true(可在配置中忽略) |
按照 website/errors/CLAUDE.md 的约定,ignorable: true表示该错误默认可以通过ignoreErrors配置排除(区别于使用->nonIgnorable()构建、无法被忽略的错误)。不过需要注意:本错误的根源是 PHP 语言层面的约束,忽略报告并不会让代码变得合法,下文会详细说明。
触发该错误的代码示例
<?php declare(strict_types = 1); class Config { /** @var string */ public readonly $name; }这段代码中,$name被声明为readonly,但只有一行 PHPDoc 注释@var string,没有任何原生类型声明,因此 PHPStan 会以标识符property.readOnlyNoNativeType报告该属性。
为什么会被报告:PHP 语言层面的硬性约束
该错误是 PHP 8.1 引入readonly属性修饰符后,由语言语义本身决定的:
- readonly 属性必须有原生类型声明。PHP 要求所有 readonly 属性都带有显式的原生类型(native type),例如
string、int、mixed等。 - 仅有 PHPDoc 类型是不够的。注释中的
@var string只是供静态分析工具与 IDE 阅读的文档性信息,运行时 PHP 引擎并不会读取它,因此不能充当类型声明。 - 这是由 PHP 引擎强制实施的语言级要求。正如 property.readOnlyNoNativeType.md 所述,该约束并非 PHPStan 的偏好设置,而是语言本身的规定——没有原生类型的 readonly 属性在任何支持 readonly 的 PHP 版本上都无法通过编译。
换句话说,当 PHPStan 报告property.readOnlyNoNativeType时,它实际上是在指出:这段代码不是合法的 PHP 代码,而不仅仅是一个类型层面的瑕疵。这也解释了为什么正确做法是修改代码而非抑制报告。
如何修复
方案一:为单一类型补充原生类型声明
既然$name的语义类型就是string,直接把 PHPDoc 注释替换为原生类型声明即可:
<?php declare(strict_types = 1); class Config { - /** @var string */ - public readonly $name; + public readonly string $name; }方案二:属性可持有多种类型时,使用联合类型或mixed
如果属性可能持有多种类型,可以使用联合类型(PHP 8.0+ 支持原生联合类型):
<?php declare(strict_types = 1); class Config { - /** @var string|int */ - public readonly $name; + public readonly string|int $name; }如果类型确实无法预先限定,mixed本身就是一个合法的原生类型声明,同样满足 readonly 的语言要求:
<?php declare(strict_types = 1); class Config { public readonly mixed $name; }方案三:配合构造函数初始化
readonly属性只能在声明它的作用域内被赋值一次,最常见的做法是在构造函数中完成初始化。补齐原生类型后,配合构造器赋值即可形成完整的合法写法:
<?php declare(strict_types = 1); class Config { public readonly string $name; public function __construct(string $name) { $this->name = $name; } }也可以使用构造器属性提升(constructor property promotion)进一步精简:
<?php declare(strict_types = 1); class Config { public function __construct( public readonly string $name, ) { } }提示:如果你对 PHPDoc 类型与原生类型的关系感兴趣,可以进一步阅读 phpdocs-basics.md 与 phpdoc-types.md。
从源码与仓库理解该规则
标识符到规则类的映射
本仓库是一个发布形态的镜像仓库(根目录包含phpstan.phar与phpstan可执行入口),规则源码位于其上游源码仓库。标识符与规则类的对应关系记录在 website/src/errorsIdentifiers.json 中,其中property.readOnlyNoNativeType(对应 JSON 第 14904–14910 行)被映射到规则类PHPStan\Rules\Properties\ReadOnlyPropertyRule,对应的源码位置为ReadOnlyPropertyRule.php(第 39 行附近)。
也就是说,property.readOnlyNoNativeType、property.readOnlyDefaultValue、property.readOnlyNotSupported、property.readOnlyStatic等同前缀标识符均出自同一个属性规则类ReadOnlyPropertyRule,只是针对 readonly 属性的不同违规维度分别报告。
readonly 错误家族一览
本仓库的 website/errors/ 目录下收录了整个 readonly 家族的官方标识符文档,以下是已确认 shortDescription 的几个核心成员:
| 标识符 | shortDescription(何时被报告) | 文档 |
|---|---|---|
property.readOnlyNoNativeType | readonly 属性缺少必需的原生类型声明 | property.readOnlyNoNativeType.md |
property.readOnly | 子类 readonly 属性覆盖了父类的可读写属性 | property.readOnly.md |
property.readOnlyDefaultValue | readonly 属性不能有默认值 | property.readOnlyDefaultValue.md |
property.readOnlyNotSupported | 配置的 PHP 版本不支持 readonly 属性(readonly 需要 PHP 8.1+) | property.readOnlyNotSupported.md |
此外,该家族还包括赋值语义相关的标识符(property.readOnlyAssignByRef、property.readOnlyAssignNotInConstructor、property.readOnlyAssignNotOnThis、property.readOnlyAssignOutOfClass等)、property.readOnlyByPhpDoc*系列(通过 PHPDoc 标注的 readonly 属性)、property.readOnlyStatic与property.readOnlyInInterface。
相邻标识符辨析:不要混淆这三类错误
property.readOnlyNoNativeType(本文):有 readonly 但没有类型,代码不合法;property.readOnlyDefaultValue:有 readonly 且有默认值,代码不合法(默认值需要移到构造函数中);property.readOnlyNotSupported:代码本身合法,但配置的phpVersion低于 8.1,readonly 语法在目标 PHP 版本上不可用。
三者分别对应「缺类型」「非法默认值」「版本不支持」三种完全不同的修复路径,排查时先分清是哪一类。
相关配置:phpVersion与错误忽略机制
设置目标 PHP 版本
readonly修饰符是 PHP 8.1 引入的特性(参见 property.readOnlyNotSupported.md 的说明)。如果你的项目确实在使用 readonly 属性,应确保 PHPStan 配置的 phpVersion 不低于 8.1:
parameters: phpVersion: 80100 # PHP 8.1按 config-reference.md 的说明:
phpVersion默认值为null,即使用当前运行 PHPStan 的 PHP 版本;- 自 PHPStan 2.0 起,还可以配置最小/最大版本区间:
parameters: phpVersion: min: 80103 # PHP 8.1.3 max: 80304 # PHP 8.3.4- 如果配置文件中未显式设置,PHPStan 会自动从最近的
composer.json推断config.platform.php版本。
该错误可被忽略,但修复代码才是正解
由于 frontmatter 中ignorable: true,你可以在phpstan.neon中通过ignoreErrors按标识符精确排除该报告。但请记住:readonly 属性缺少原生类型是由 PHP 引擎强制实施的语言级要求,抑制 PHPStan 报告并不能让代码通过 PHP 编译。因此,正确的处理方式是修改代码补齐原生类型,而不是在配置中忽略。关于ignoreErrors的完整语法与「未匹配的忽略报告」等细节,可参阅 ignoring-errors.md。
延伸阅读
- 本文依据的官方标识符文档:property.readOnlyNoNativeType.md
- 标识符与规则类映射表:website/src/errorsIdentifiers.json(
property.readOnlyNoNativeType位于第 14904–14910 行) - 错误文档的生成规范与结构约定:website/errors/CLAUDE.md
- readonly 家族的其余标识符文档:website/errors/property.readOnlyDefaultValue.md、website/errors/property.readOnlyNotSupported.md、website/errors/property.readOnly.md
phpVersion配置详解:website/src/config-reference.md- 错误忽略机制:website/src/user-guide/ignoring-errors.md
- 开发工具
- 代码质量
- 静态分析
【免费下载链接】phpstan
PHP Static Analysis Tool - discover bugs in your code without running it!
相关推荐
PHPStan 错误标识详解:property.phpDocType —— 属性 PHPDoc 类型与原生类型声明不一致
PHPStan 错误标识详解:property.phpDocType —— 属性 PHPDoc 类型与原生类型声明不一致 property.phpDocType
开发工具代码质量静态分析PHPStan 错误标识符 `missingType.property` 深度解析:属性缺失类型声明的检测、修复与配置
PHPStan 错误标识符 missingType.property 深度解析:属性缺失类型声明的检测、修复与配置 导读 missingType.propert
开发工具代码质量静态分析PHPStan 错误详解:property.extraNativeType —— 子类属性多出的原生类型声明
PHPStan 错误详解:property.extraNativeType —— 子类属性多出的原生类型声明 PHPStan 是 PHP 的静态分析工具,能够在
开发工具代码质量静态分析
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考