Objects must always be in a valid state. This means that the object always behaves (methods) and contains information (member variables) that make sense. The purpose of a constructor is to create the object in a valid state.
In consideration of value objects, the constructor must take the minimum number of arguments such that the object makes sense. For example, if you had an RGB value object, would it make sense in your application if red was the string "monkey", green was NULL, and blue was an array?
final class RGB {
$r, $g, $b;
}
$mycolor = new RGB;
// NULL, what value of red is that supposed to be?
var_dump($mycolor->r);
// We are free to set these values too, even though they do not make sense.
$mycolor->r = 'monkey';
$mycolor->g = NULL;
$mycolor->b = array('foo', 'bar');
That is exactly what this object allows to happen. $mycolor references an object that is not in a valid state. How can we ensure that an RGB object always has three values, red, blue, and green, and that they are all numbers between 0 and 255?
final class RGB {
private $r;
private $g;
private $b;
public function __construct($r, $g, $b) {
// are our arguments numbers?
if (!is_numeric($r)) {
throw new Exception('Value of red must be a number');
}
if (!is_numeric($g)) {
throw new Exception('Value of green must be a number');
}
if (!is_numeric($b)) {
throw new Exception('Value of blue must be a number');
}
// are our arguments within range 0-255?
if ($r < 0 || $r > 255) {
throw new Exception('Value of red must be 0-255');
}
if ($g < 0 || $g > 255) {
throw new Exception('Value of green must be 0-255');
}
if ($b < 0 || $b > 255) {
throw new Exception('Value of blue must be 0-255');
}
// our arguments are fine.
$this->r = $r;
$this->g = $g;
$this->b = $b;
}
//*// Canadian support
public function getColour() {
return $this->getColor();
}
public function getColor() {
return array($this->r, $this->g, $this->b);
}
}
$mycolor = new RGB; // error! missing three arguments
$mycolor->r = 'monkey'; // error! this field is private
// exception! the constructor complains about our values not being numbers
$mycolor2 = new RGB('monkey', NULL, array('foo', 'bar'));
// exception! the constructor complains our numbers are not in range
$mycolor3 = new RGB(300, 256, -10);
$mycolor4 = new RGB(255, 0, 0); // ahh... a nice shade of red
var_dump($mycolor4->getColor()); // we can read it out later when we need to
If your constructor requires three arguments, and it throws an exception unless all three are numbers between 0 and 255, you will always be defining the member variables with good values.
You must also make sure that the red, blue, and green member variables are private. Otherwise, anyone can write anything they want to them. Of course, if they are private no one can read them either. To create a read-only operation we define the getColor() method that accesses the private member variables for us.
This version of the RGB object will always have a valid state.
Hopefully this sheds some light on the nature of OOP and gives you a place to start thinking from.