PHP 8.3:未修改readonly属性却触发无法修改只读属性错误
错误原因分析
你遇到的问题核心在于readonly属性的初始化规则:
- PHP的
readonly属性只能在声明该属性的类的构造函数中被初始化一次,一旦初始化完成,就无法再被修改(包括子类或父类的构造函数都不能再次赋值)。 - 你的代码中,
ImportFactoryAbstract(子类)和XmlLeafListAbstract(父类)都声明了protected readonly AppConfig $appConfig和protected readonly array $list属性。当子类构造函数调用parent::__construct()时,父类构造函数会尝试再次给这些readonly属性赋值,但此时这些属性已经被子类的构造函数初始化过了,违反了readonly属性的不可修改规则,因此触发致命错误。
解决思路与代码修正
最直接的修复方式是移除子类中重复声明的readonly属性,因为父类已经定义了这些属性,子类可以直接继承并使用,不需要重复声明:
修正后的ImportFactoryAbstract类代码:
abstract class ImportFactoryAbstract extends XmlLeafListAbstract { public function __construct( AppConfig $appConfig, array $list, ) { // do some stuff $unhandledXmlElements = []; parent::__construct($appConfig, $unhandledXmlElements, $list); // do some more stuff } }
补充说明
- 子类构造函数不再声明
protected readonly属性,而是直接将参数传递给父类构造函数,由父类负责初始化readonly属性,这样就避免了重复赋值的问题。 - 如果子类需要在构造函数中使用这些属性,因为已经继承了父类的属性,直接通过
$this->appConfig和$this->list访问即可,无需重新声明。
如果有特殊需求必须在子类中处理这些属性,还可以考虑:
- 不使用
readonly修饰符,改用私有属性+只读getter方法的方式控制属性不可修改。 - 调整类的继承结构,避免父类和子类重复声明相同的readonly属性。
内容的提问来源于stack exchange,提问作者Andrew Sohn
相关产品推荐
相关产品推荐

