【发布时间】:2018-05-11 13:29:53
【问题描述】:
我有一个类,我想使其不可变,但该类有很多属性。
<?php
class Gameworld {
/** @var string */
private $name;
/** @var string */
private $type;
/** @var bool */
private $is_online;
/** @var int */
private $online_players;
/** @var int */
private $online_players_record;
/** @var string */
private $description;
/** @var string */
private $location;
/** @var \DateTime */
private $created_at;
}
如何创建这样的对象?当我介绍带有所有这些属性的public function __construct() 时,它会变得臃肿。如果我引入 setter,它将不再是不可变的。
编辑:我正在考虑制作二传手,但只能使用一次。多亏了这一点,我不会有臃肿的构造函数,但由于某种原因,这似乎不是一个好主意。就像是:
class Gameworld {
... old properties ...
/** @var array */
private $used_setters = [];
public function setName(string $name){
if(in_array('name', $this->used_setters)){
throw new ImmutableException('Class Gameworld is immutable.');
}
$this->name = $name;
$this->used_setters[] = 'name';
}
}
【问题讨论】:
-
私有属性不是不可变的。你需要常量。
-
有一个RFC for that,但仍在讨论中。看看金钱比较。
-
@GabrielHeming 我知道那个 RFC,但我正在寻找当前状态的解决方案。它仍然不能解决我的问题,因为我需要创建填充了所有这些属性的对象,我正在考虑要么制作丑陋的
public function __construct(string $name, string $type, bool $is_online, int $online_players, int $online_players_record, string $description, string $location, \DateTime $created_at),要么使用反射和setAccessible填充这些属性的 Hydrator。 -
只有两种方法可以在不创建新对象的情况下填充不可变对象。使用它的
__construct(它确实创建了一个对象,但不是一个新对象)或通过反射(有很多库可以做到这一点)。如果您使用set方法(没有问题),它将始终创建一个新对象,而原始对象仍然是不可变的。但是,如果您只想创建一个不改变其属性的对象,甚至随着时间的推移创建一个新对象,请使用常量并阻止__clone。顺便说一句,为什么这是不可变的?也许另一种方法可以解决您的问题。 -
所有属性都应该是不可变的吗?还是只有一些?如果是这样,哪些?可能的值是什么?
标签: php immutability