I've got a class that I want to make immutable but that class has a lot of properties.
<?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;
}
How to create such object? When I introduce public function __construct()
with all those properties it will get bloated. If I introduce setters it won't be immutable anymore.
EDIT: I was thinking about making setters but ones that could be only used once. Thanks to that I won't have bloated constructor but for some reason it seems not like a good idea. Something like:
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';
}
}
I would use __set() magic method to check if the value is set else I would throw an exception:
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 __set($property, $value)
{
if (property_exists($this, $property)) {
if(is_null($this->$property)){
$this->$property = $value;
return $this;
}
throw MyCustomException();
}
throw UndefinedClassVariableException();
}
}
A basic usage would be:
$x = new Gameworld();
$x->name = "OK";
$x->is_online = true;
$x->name="Exception";
P.S: Exceptions must extend the base exception class or you could trigger or log an error, depends on what you want
P.S.S: An alternative sollution would be to use __call() method and check if the value is null
I would suggest passing properties as an array argument like
__construct( array $properties )
{
$this->property = $properties['property'];
....
}