首页/新闻资讯/正文详情

PHPStan 错误指南:`property.readOnlyByPhpDocAssignNotOnThis` —— @readonly 属性为何必须赋值在 $this 上

发布时间:2026/9/24 17:05:57 来源:云帆数科 栏目:资讯中心
PHPStan 错误指南:`property.readOnlyByPhpDocAssignNotOnThis` —— @readonly 属性为何必须赋值在 $this 上
PHPStan 错误指南property.readOnlyByPhpDocAssignNotOnThis—— readonly 属性为何必须赋值在 $this 上【免费下载链接】phpstanPHP Static Analysis Tool - discover bugs in your code without running it!项目地址: https://gitcode.com/gh_mirrors/ph/phpstan本文以 PHPStan 官方错误标识error identifier文档 property.readOnlyByPhpDocAssignNotOnThis.md 为骨架结合仓库中 PHPDoc 基础文档 及 错误标识索引 中记录的规则实现深入讲解readonly属性在构造函数内赋值时为何必须作用于$this、该错误在什么场景触发以及三种可落地的修复方案。读完本文你将理解 PHPStan 只读语义的完整约束边界并能用ignoreErrors精确忽略这类误报。错误概览何时触发本标识错误标识property.readOnlyByPhpDocAssignNotOnThis英文短描述readonlyproperty is assigned on a different instance instead of$this.readonly属性被赋值到了另一个实例上而不是$this。所属规则类PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyAssignRule见 errorsIdentifiers.json 中 2.3.x 分支的规则定位可忽略性ignorable: true即该错误可通过ignoreErrors配置精确忽略说明中允许开发者针对特定代码位置豁免此检查。触发场景与完整代码示例以下代码会让 PHPStan 报出该错误?php declare(strict_types 1); class Foo { /** readonly */ public int $value; public function __construct(self $other) { $other-value 10; // ERROR: readonly property Foo::$value is not assigned on $this. } }关键点在于构造函数参数是同类self的另一个实例而赋值操作$other-value 10的目标对象是$other而不是当前正在构造的对象$this。与之形成对比的是合法写法——在构造函数里对$this赋值是允许的?php declare(strict_types 1); class Foo { /** readonly */ private int $value; public function __construct(int $value) { $this-value $value; // OK } }为什么会报告此错误readonly 的契约边界根据 property.readOnlyByPhpDocAssignNotOnThis.md 的说明该错误基于以下语义readonly属性只应被赋值一次且赋值时机限定在“初始化阶段”。PHPStan 将初始化阶段界定为声明类自身的构造函数内部。构造函数内的赋值必须作用于$this。赋值到同一类的其他实例并不算“初始化本对象”因为它修改的是另一个对象的状态——该对象可能早已完成初始化。这就违背了 readonly 契约。与相邻错误标识的边界区分readonly校验并非只有一个标识理解这一点有助于准确归类报错。从 errorsIdentifiers.json 可以看到ReadOnlyByPhpDocPropertyAssignRule这条规则同时产出多个标识各自对应不同的违约形式错误标识触发条件property.readOnlyByPhpDocAssignOutOfClass在声明类外部给readonly属性赋值例如其他类中$foo-value 42;对应 property.readOnlyByPhpDocAssignOutOfClass.mdproperty.readOnlyByPhpDocAssignNotInConstructor在声明类内部但构造函数之外的方法中对$this的readonly属性赋值对应 property.readOnlyByPhpDocAssignNotInConstructor.mdproperty.readOnlyByPhpDocAssignNotOnThis在构造函数内给readonly属性赋值但赋值目标是同类实例而非$this本文主题property.readOnlyByPhpDocAssignByRef以引用by-ref方式传递readonly属性见ReadOnlyByPhpDocPropertyAssignRefRuleproperty.readOnlyByPhpDocDefaultValuereadonly属性声明了默认值见ReadOnlyByPhpDocPropertyRule换言之ReadOnlyByPhpDocPropertyAssignRule从“赋值位置”类外/类内构造函数外与“赋值目标”非$this的实例两个维度分别判定违约类型本文讨论的是“位置合法构造函数内但目标不合法非$this”的中间情形。设计意图为什么不允许给同类的其他实例赋值即使$other与$this属于同一个类$other也是一个独立对象。它的readonly属性应当由它自己的构造函数初始化。在另一个对象哪怕同类的构造函数里改写它等于绕过了该对象自身的初始化流程破坏了“只读属性不可二次写入”的不变式。这正是文档中“assigning areadonlyproperty on a different object instance violates the readonly contract because it modifies state that may have already been initialized”的含义。修复方案一改为在 $this 上初始化推荐如果$other实例的值确实只是用来作为初始化数据那么应该把构造函数的入参从对象改为标量值并在$this上赋值?php declare(strict_types 1); class Foo { /** readonly */ public int $value; - public function __construct(self $other) public function __construct(int $value) { - $other-value 10; $this-value $value; } }这样既保留了readonly的不可变性约束又让初始化发生在当前对象的构造函数内符合契约。修复方案二去掉 readonly 注解允许跨实例写入如果业务上确实需要让同类的不同实例之间互相改写属性例如克隆后同步状态则应移除readonly注解放弃只读约束?php declare(strict_types 1); class Foo { - /** readonly */ public int $value; public function __construct(self $other) { $other-value 10; } }移除注解后该属性恢复为普通可变属性PHPStan 不再对此赋值行为做任何只读校验。修复方案三类级/属性级只读语义的配套工具除上述直接修复外PHPStan 还提供若干配套机制可结合场景选择phpstan-allow-private-mutation与readonly组合当希望“对外只读、类内部允许变更”时使用组合写法phpstan-readonly-allow-private-mutation等价于同时声明两者。参见 phpdocs-basics.mdclass Foo { /** * readonly * phpstan-allow-private-mutation */ public int $counter 0; /** phpstan-readonly-allow-private-mutation */ public string $name ; public function increment(): void { $this-counter; // OK - private mutation is allowed $this-name foo; // OK } } (new Foo())-counter 5; // Error: readonly property Foo::$counter is assigned outside of its declaring class.类级immutable/readonly把类标记为不可变后PHPStan 会将类的所有属性视为只读/** immutable */ class Foo { public string $bar; } (new Foo())-bar baz; // readonly property Foo::$bar is assigned outside of its declaring class.with*不可变更新模式与其在类内“原地修改”只读属性会触发property.readOnlyByPhpDocAssignNotInConstructor不如返回携带新值的新实例这也是 property.readOnlyByPhpDocAssignNotInConstructor.md 推荐的替代做法class Foo { /** readonly */ private int $value; public function __construct(int $value) { $this-value $value; } public function withValue(int $newValue): self { return new self($newValue); } }将本错误加入 ignoreErrors可选由于该标识声明了ignorable: true当团队经过评审确认某处跨实例赋值是刻意设计例如序列化/反序列化框架的回填逻辑可以在phpstan.neon中按标识精确豁免parameters: ignoreErrors: - identifier: property.readOnlyByPhpDocAssignNotOnThis path: src/Persistence/*.php不过需要注意精确忽略应只用于经过评审的例外。readonly的核心价值在于把“只读”约束交给静态分析在编码期强制执行规避此类行为是首选忽略只是兜底手段。小结property.readOnlyByPhpDocAssignNotOnThis是 PHPStan 对readonly属性在构造函数中“赋值目标错误”的静态检查结果。其背后规则ReadOnlyByPhpDocPropertyAssignRule与类外赋值...AssignOutOfClass、类内非构造函数赋值...AssignNotInConstructor等标识共同构成一套完整的只读契约校验体系。实践中优先把初始化收敛到$this需要跨实例写入时再权衡去掉注解或使用phpstan-allow-private-mutation即可在保持代码不可变性的同时让 PHPStan 检查结果清晰可控。【免费下载链接】phpstanPHP Static Analysis Tool - discover bugs in your code without running it!项目地址: https://gitcode.com/gh_mirrors/ph/phpstan创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

shadcn-vue Popover 组件完全指南:安装、源码结构与实战用法
shadcn-vue Popover 组件完全指南:安装、源码结构与实战用法

UI组件前端 【免费下载链接】shadcn-vue Vue port of shadcn-ui 项目地址: https://gitcode.com/gh_mirrors/sh/shadcn-vue 点击查看 免费下载 Popover(弹出层)是 shadcn-vue 中最常用的交互组件之一,它由触发按钮驱动&#xff0… · 2026/9/24 17:05:57

OpenJarvis Showcase 投稿指南:面向结果优先的本地 AI 用例社区与 Markdown 条目规范
OpenJarvis Showcase 投稿指南:面向结果优先的本地 AI 用例社区与 Markdown 条目规范

【免费下载链接】OpenJarvis Personal AI, On Personal Devices 项目地址: https://gitcode.com/gh_mirrors/op/OpenJarvis 点击查看 免费下载 OpenJarvis 是一个运行在个人设备上的个人 AI 项目(Personal AI, On Personal Devices)&#xf… · 2026/9/24 17:05:39

PHPStan 错误 requireImplements.onEnum 详解:`@phpstan-require-implements` 误用于枚举(enum)的修复方案
PHPStan 错误 requireImplements.onEnum 详解:`@phpstan-require-implements` 误用于枚举(enum)的修复方案

开发工具代码质量静态分析 【免费下载链接】phpstan PHP Static Analysis Tool - discover bugs in your code without running it! 项目地址: https://gitcode.com/gh_mirrors/ph/phpstan 点击查看 免费下载 requireImplements.onEnum 是 PHPStan 在检测到 PHPDoc… · 2026/9/24 17:05:39

清蒸鳜鱼全解析:从“淡水鱼之王”的经典做法到 RAG 菜谱数据的结构化价值
清蒸鳜鱼全解析:从“淡水鱼之王”的经典做法到 RAG 菜谱数据的结构化价值

教程人工智能大模型RAG 【免费下载链接】all-in-rag 🔍大模型应用开发实战一:RAG 技术全栈指南,在线阅读地址:https://datawhalechina.github.io/all-in-rag/ 项目地址: https://gitcode.com/datawhalechina/all-in-ra… · 2026/9/24 17:42:29

AI大模型落地秘籍:小白程序员必备的收藏攻略,解锁企业增长新机遇!
AI大模型落地秘籍:小白程序员必备的收藏攻略,解锁企业增长新机遇!

本文深入剖析企业AI部署失败原因,指出95%的AI试点未能产生财务影响的关键在于流程对接缺失。文章强调选择高频、重复、可容错且有数据的场景至关重要,并重新排序企业AI架构层级:业务接口优先,数据中台、AI中台、技术底座依次重要。… · 2026/9/24 17:42:23

小白程序员必看:大模型如何赋能制造企业,实现AI自主运营?
小白程序员必看:大模型如何赋能制造企业,实现AI自主运营?

文章探讨了制造企业数字化深水区面临的挑战:数据虽多但缺乏持续理解和转化。介绍了Operation Agent Brain(AI全自主运营分析及优化平台),它不是新增系统,而是企业现有数字化基础上的AI智能中枢。OAB通过连接各类业务系… · 2026/9/24 17:42:23

测量OP27G的噪声
测量OP27G的噪声

测量OP27G的低频噪声OP27G Datasheet 01 【测量 OP27G 的噪声】 一、测试电路 在运放OP27的数据手册中, 给出了OP27G的噪声电压测试电路 这个电路是测试运放0.1赫兹到10赫兹之间的噪声, OP27被设置成增益为50k的放大状态, 它的输出再通过低… · 2026/9/24 17:42:16

105V高压电源设计:从需求到选型的完整计算过程
105V高压电源设计:从需求到选型的完整计算过程

很多电源设计资料只给公式和结果,不讲推导过程。这篇文章完整记录了一个105V高压电源的设计计算过程,从需求分析到每一个电阻、电容、电感、MOS管的选型依据。所有公式都有推导,所有参数都有验证。01 设计需求先明确电源的性能指标要求&#… · 2026/9/24 17:42:10

小白程序员必看:轻松入门大模型时代下的Agent、Skill与MCP
小白程序员必看:轻松入门大模型时代下的Agent、Skill与MCP

本文深入浅出地介绍了大模型(LLM)及其在AI领域的新发展,重点讲解了Agent、Skill和MCP的概念及其相互关系。阐述了LLM作为“大脑”负责理解和决策,Agent作为“行动者”执行任务,Skill是Agent的具体能力模块,… · 2026/9/24 17:42:04

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码