Reputation: 805
I've got quite a few POPO's (Plain Old PHP Objects) in my codebase, some of which contain in excess of 30 fields. Some of these objects have many required fields, as well as many optional fields (some of which set defaults.)
Here's a simplified version of one of these classes:
Class POPO {
private $required;
private $alsoRequired;
private $defaultSet = 100;
private $optional;
private $alsoOptional;
public function __construct() {
//some constructor code
}
public function setRequired($required) {
//validate here
$this->required = $required;
}
//other setters
...
}
My question is about best practices. I figure for instanciating the object and setting the values, I have two options:
I could create a constructor that contained default values for non required fields, and use setters for the optional stuff:
public function __construct(
$required,
$alsoRequired
) {
$this->setRequired(1);
$this->setAlsoRequired(2);
}
$POPO1 = new POPO(1,2); //to instanciate new object w/ only required fields.
$POPO1->setOptional(3); //to set optional fields
I could create a constructor that contained all fields, using optional parameters:
public function __construct(
$required,
$alsoRequired,
$optional = null,
$alsoOptional = null
) {
$this->setRequired($required);
$this->setAlsoRequired($alsoRequired);
$this->setOptional($optional);
$this->setAlsoOptional($alsoOptional);
}
$POPO1 = newPOPO(1,2); //instanciate new object w/ only required fields.
$POPO2 = newPOPO(1,2,3,4); //instanciate object w/ optional fields.
This gets confusing when adding or removing params from the class. Every instance where the class is used has to be updated. The same is true for option 1, but to a lesser extent.
A thrid option occured to me to have a no param constructor and use setters for everything, but this would allow the object to be in an invalid state.
So my question is, which of these two options is the better way?
Maybe there is another better way I'm not thinking of?
How about handling default values? Should that be done only via setter?
Upvotes: 2
Views: 2358
Reputation: 1902
So my question is, which of these two options is the better way?
If you have too many parameters, option 1 (required values in constructor, optional in setters) would be more readable.
A third option occured to me to have a no param constructor and use setters for everything, but this would allow the object to be in an invalid state.
I would not recommend having objects in invalid states at any time inside your code.
Maybe there is another better way I'm not thinking of?`
class POPO
{
protected $conf;
public function __construct(PopoConfiguration $conf)
{
$this->conf = $conf;
}
// From now on, use $this->conf getters
}
class PopoConfiguration
{
protected $required;
protected $alsoRequired;
protected $defaultSet = 100;
protected $optional;
protected $alsoOptional;
public function __construct(/* required params */)
{
// ...
}
// Getters and setters
}
$popoConf = new PopoConfiguration();
// Manipulate your configuration here
$popoConf->setAlsoOptional(42);
// ...
// Instantiate POPO
$popo = new POPO($popoConf);
One good practice is to document PopoConfiguration as best as you can, so anyone can know exactly what they can (and can't) do to configure a POPO object.
How about handling default values? Should that be done only via setter?
If there are many parameters (the number of parameters affect the readability), it's best to do it via setters only.
Upvotes: 1
Reputation: 3950
This gets confusing when adding or removing params from the class.
A class should be open for extension but closed for modification - the "O" in "SOLID"
A cleaner approach could be to pass an array to constructor. You may choose to have two separate arrays - one for required attributes and second for optional.
Additionally, multiple constructors may also be employed, if required.
Upvotes: 0