PHP 8修改getter返回DateTime意外变更类私有属性问题
问题原因
你存在的认知遗漏是:PHP 中基础类型(字符串、整型、浮点型、布尔型等)的赋值、返回默认是值传递,会生成副本;但对象类型的赋值、返回默认传递的是对象标识符副本,所有持有该标识符的变量都指向同一个对象实例。
你代码中用到的DateTime是典型的可变对象,它的add()方法会直接修改对象自身的属性,不会生成新对象。你通过getStart()拿到的$end和类私有属性$gStart指向完全相同的DateTime实例,对$end调用add()方法自然会修改原属性的值,和引用操作的表现一致。
修复方案
你可以根据业务场景选择以下任意一种方案:
- 操作前先克隆对象,生成独立副本后再修改
public function getEnd(): ?\DateTimeInterface { $end = $this->getStart(); if ($end === null) { return null; } $end = clone $end; $gInterval = new \DateInterval('P90D'); $end->add($gInterval); return $end; }
- 更换为不可变的
DateTimeImmutable类型存储时间,ORM 列类型对应修改为datetime_immutable,该类型的add()方法会返回全新的对象实例,不会修改原对象
/** * @ORM\Column(type="datetime_immutable") */ private ?\DateTimeImmutable $gStart = null; public function getStart(): ?\DateTimeInterface { return $this->gStart; } public function getEnd(): ?\DateTimeInterface { if ($this->getStart() === null) { return null; } $gInterval = new \DateInterval('P90D'); return $this->getStart()->add($gInterval); }
- 直接在 getter 方法中返回克隆对象,从源头避免外部修改类的内部属性
public function getStart(): ?\DateTimeInterface { return $this->gStart ? clone $this->gStart : null; }
内容的提问来源于stack exchange,提问作者user3440145
相关产品推荐
相关产品推荐

