After writing some classes where class initialization requires multiple options, instead of writing several parameters into constructors or setters, I started passing an associative array of parameters, which I called $options
, where, for example:
$options = {'productLine' = $productLine, 'modelNumber' => $modelNumber, ... };
My concern is that using such structure can lead to undesirable consequences.
Consider the following code, where by reading private variables, you pretty much know what this class needs to operate itself:
class Generator
{
private $productLine;
private $modelNumber;
private $motorPresent;
//... 5 similar lines
function __construct($options)
{
$productLine = $options['productLine'];
$modelNumber= $options['modelNumber'];
$motorPresent= $options['motorPresent'];
//... 5 similar lines
}
}
Now, consider this code, where by reading private variables, you do not really know what is being passed to it, other than some “parameters”.
class Generator
{
private $options;
function __construct($options)
{
$this->options = $options;
}
}
It is not immediately clear what parameters are being passed from the source — you have to know the actual $options
array to know what is being passed. To know what’s going on you have to read the code, and that takes time. Tests can be used to pass some sample parameters, but I wouldn’t depend on tests as being the real answer.
My question is:
- is there a way to keep assignments simple (like in my second code, code in constructor remains the same whether there are 10 parameters or 20), and yet still keep the class signature immediately apparent?
My current answer would be to either write code as in my first example, elaborating on which variable gets assigned what, but I feel that first way is needlessly verbose and I don’t like it, because it introduces extra variable passing, when the variables are already in $options, just use $options[‘var_name’] instead.
Another way is to use comments, but that’s not very good since comments are not always maintained as well as the code itself.
4
One possible answer is to check that all operating conditions have been set correctly as such:
function __construct($options)
{
//check that everything is set properly
if (!isset($options['productLine']))
throw new InvalidArgumentException("We need to know Product Line");
if (!isset($options['modelNumber']))
throw new InvalidArgumentException("We need to know Model Number");
}