Home

Blog

Trains

16mm Guide

Suppliers

Ride-On Trains

Other Scales

Miscellaneous

Web Design

Links

FAQ

Contact Me

Object Oriented Programming

(for Web Developers)
...in which Andy describes the basics of Object Orientated programming with examples in PHP and Javascript

Lesson 2: More on Classes: Constructors, Destructors and Encapsulation

In the previous lesson, I introduced the basics of objects, and explained how a method provides functionality within it.

Another way of looking at an Object is that it's a collection of information about a "thing". Imagine you are trying to represent a circle in a program. You might have Properties of the circle, such as its radius, and its position (usually the X and Y position of the centre). You could store it in some kind of memory structure. In pseudo-code, this might look like:

    mycircle = {
		radius  => 12,
		centreX => 400,
		centreY => 300
	};
You can set the radius with something like mycircle.radius=14, and you can retrieve it with r=mycircle.radius. But in a procedural language, you would have to get hold of the area with a function, something like area=circle_get_area(mycircle.radius). Wouldn't it be great if we could "extend" our data structure like this (again, this isn't in PHP)
    mycircle = {
		radius  => 12,
		centreX => 400,
		centreY => 300,
		area => function( PI * this.radius
		    * this.radius * 2),
	};
That's exactly what object oriented programming allows you to do.

So, let's get back to the PHP and write this circle thing as a PHP object. We want to create a circle and give it a radius in one step, then we want to be able to set the centre position.

class Circle {
	$radius = 1;
	$x = 0;
	$y = 0;
	$PI = 3.14159;
	function __construct( $r) {
		$this->radius = $r;
	}
	function setPosition($x, $y) {
		$this->x = $x;
		$this->y = $y;
	}
	function area() {
		return ( $this->PI * $this->radius 
			* $this->radius * 2);
	}
}
We now have the object shown above. it has properties (radius, x , y and PI), and methods (setPosition() and area() ). Note also a special method called __construct. (that's two underscores on the front.) This special method is used when we create the instance of the object; it's called the Constructor. You might use it to initialise your instance, and set things up. It will always be called when you create an instance, which you do using new:
$roudyroundy = new Circle(12);
There's a similar magic method you can use when you need to destroy an object, which can free up resources when you've finished with it. It's called a Destructor and in PHP, it has the name __destruct() (and it takes no arguments).

If you write programs which don't consume much memory, or which are short-lived, you don't usually have to bother with a destructor: the memory will be recovered when the program terminates anyway.

Encapsulation

After posting the last lesson, someone asked me why I should bother with a method which simply returns a value. Let's put the question in the context of today's "Circle" object.

Imagine you have your Circle class, and it contains the following method:

function getRadius() {
	return $this->radius;
}
At first, this seems pretty meaningless. After all, the following two lines are equivalent, aren't they?
$r = $myCircle->radius; // fetch a property
$r = $myCircle->getRadius(); // call a method
On their own, yes, these sort of methods are pointless. However, they provide an important feature of object orientation called Encapsulation. This is the ability to hide the implementation details of an object, and expose a fixed (and documented) interface to the user.

Encapsulation gets its name from the idea of wrapping things up in a bubble, which cannot be accessed from the outside. We can use this to lock down how someone might communicate with our object, and prevent them from playing around with the internal representation. As a silly example, maybe we want to represent the radius within our object in millimetres, for a reason which is best known to us, and need not concern any users of our object, and expose it to the user in metres (daft inside a computer, but stick with me...). In that case, the method would look like this:

function getRadius() {
	return $this->radius / 1000;
}
and would give you a different value than if you read $myCircle->radius directly. I've given a silly example to explain the idea. In practice, there may be many reasons why you don't want the internals of your object to be played with, one of which is that you could improve the algorithms inside your object, and as long as the users always use the same methods to get at it, they don't need to change and code.

What we'd like to do in this case is physically prevent anyone from getting at the bits of our object we don't want them to see. We can do this in many languages, including PHP. with keywords Public and Private. (We will discuss the third one of these, Protected, in a later lesson).

class Circle {
    private $radius = 1;
    private $x = 0;
    private $y = 0;
    private $PI = 3.14159;
	
    public function __construct( $r) {
        $this->setRadius($r);
    }
    public function setPosition($x, $y) {
        $this->x = $x;
        $this->y = $y;
    }
    public function area() {
        return ( $this->PI * $this->getRadius() 
            * $this->getRadius() * 2);
    }
    public function getRadius() {
        return ( $this->radius );
    }
    public function setRadius($r) {
        $this->radius = $r;
    }
}
This has the effect of preventing anyone from getting at the things we've marked as private. Both Properties and Methods can be marked private or public as required, although in "pure" OO, it's rare to have a public property: everything is accessed through method calls. (it's supposed to be tidier or something).

You'll notice in the example above that I've also made use of my public methods as much as I can within my own class definition. I don't really need to call setRadius() to set the radius, but if I change the implementation, it should mean I have far less code to change.

One other thing: the methods which are public ( the constructor, setPosition(), area(), getRadius() and setRadius() in this case) are called the Interface, often abbreviated to the API (Application Programmers' Interface). It's common to write tests to exercise all the public methods on your object. This then shows you if anything has broken. Unit Tests and Test Driven Development are concepts that rely on the idea of Encapsulation.

The third Encapsulation type, Protected will be discussed later when we get on to Inheritance

Now, in the first lesson, I started talking about objects that create lumps of HTML, and in this lesson, I've gone off on a tangent about objects that do something completely different. Just before we finish for today, I'm going to extend the object I talked about last time, to include the concepts mentioned here.

Remember, we had an object with the following methods:

  • setValues() -- defines the list of items to show
  • setValue() -- defines the item to display initially
  • render() -- draws it
  • writeOption() -- to be used by our DropDownBox class only
We haven't got a constructor yet. It would be useful to create some defaults, so that we can draw the dropdown without setting some values:
class DropDownBox {
    public function __construct( $initialVal ) {
        $this->setValue($initialVal);
        $this->setValues( array("x" => "empty list"));
    }
    // the rest of the code
}
You'll see I've added the constructor, and it takes one parameter. This is the initial value for the dropdown. The constructor also sets up a dummy list so that the thing will draw, even if we don't add our own list.

You now need to supply a parameter when you create the object:

$box = new DropDownBox("apples");
Note also that I've made the constructor public (it would be useless if it were made private, wouldn't it!!). The other methods discussed in the last lesson should be set as follows:
  • setValues() -- public: we want users to change the available values.
  • setValue() -- public: we want users to change the selected value.
  • render() -- public: we want users to draw the thing.
  • writeOption() -- private: this is for internal use only.
The "writeOption()" method is not meant to be used by anyone outside; it's only to be used within the "render()" method. It's a separate method because it does a useful and specific thing, but we don't want people calling $myDropDown->writeOption() willy-nilly; that might lead to bad HTML. By making it private, it's inaccessible from the outside. This is a good example of Information Hiding. We're hiding the internal mechanics of the <select> tag from the end-user, and that's a good thing.

That's enough for today. In the next lesson, we'll look at Inheritance, Abstraction and Polymorphism.

GRG