views:

247

answers:

2

Hi,

I've just started to learn PHP OOP, previously I have been doing PHP in a procedural manner. I was reading this article and I've got a couple of quick questions,

  1. How is the constructor for value objects commonly defined? As one that takes in all "data members" as parameters or stick to the default constructor and use mutator / accessor methods to set / get data members?

  2. Is this actually the recommended way to start doing PHP OOP? Cos honestly, the concepts explained in the article was a tad confusing for me.

Cheers

+1  A: 
  1. To build objects that act as neutral data containers I would use classic constructor __contruct() you can then use magic __get and __set to access properties. Another way in to inject data with db row object for instance , you can found more information on this by googling 'dependency injection'

  2. You can start it as in most OOP languages via a Main class, but for web concerns MVC is widely used.

Do you have a previous OOP programming experience ?

Benoit
A: 

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.

erisco