Tuesday, April 20, 2010

Getting Started with OOP & PHP5

Since the introduction of PHP 5 in 2004, PHP has had an object model worthy of that description and became a truly modern language for use on the web. Earlier PHP scripts would have been of the kind where, to quote from Alice's Adventures, you would `"Begin at the beginning, and go on till you come to the end: then stop."
Nowadays that very procedural approach is less common in PHP, so this article takes a look at some of the basic object oriented features available in the language and shows some examples of using them with code examples.

Using OOP (Object Orientated Programming) enables us to architect our systems much more clearly, and to make them more manageable and more maintainable. This technique also allows us to separate form from function to create clean, navigable codebases with plenty of opportunities to reuse code, apply design patterns and bring in concepts from other brances of computer science.

Objects vs Classes

While the terms "object" and "class" are often used almost interchangeably in the world of software, there is a definite conceptual difference between the two. A class is the blueprint or recipe; it describes what the object should be, have and do. So a class might look like this:
class Elephpant {
    public $colour;

    public function dance() {
        echo "elephpant dances!\n";
        return true;
    }
}
elephpant.php
An object, on the other hand, is an actual instantiation of the class – its an actual thing, with values and behaviours. In the example below, $ele is the object:
include('elephpant.php');

$ele = new Elephpant();
We can inspect $ele to make sure that it is, in fact, an object of the class Elephpant, using the print_r command. Adding this to our code sample as shown, we see the output below:
include('elephpant.php');

$ele = new Elephpant();
print_r($ele);

Elephpant Object
(
    [colour] =>
)
This output shows an object, of type Elephpant, and with a single empty property named "colour". For more information about the objects exact properties and their values, you can also use var_dump, which gives a more detailed output showing in detail the datatypes of each property. This is particularly useful for spotting empty strings, nulls and false.

Using Objects, Their Properties and Methods

Our class, Elephpant, has a property and a method (OO-speak for "function") already defined inside it, so how can we interact with these? Let's start by setting the colour property; we use the object operator which is a hyphen followed by a greater than sign.
include('elephpant.php');

$ele = new Elephpant();

// set the colour property
$ele->colour = "blue";

// now use that property
echo "The elephpant is " . $ele->colour;
The output of this script reads "The elephpant is blue". The property will remain set on the object until the object is destroyed, or the property overwritten or unset. Objects are a great way of keeping things together that belong together, for example information about an elephpant!
Similarly we can call the method using the same operator – the brackets after the call let PHP know its a method rather than a property, and if we had parameters to pass in they'd go between the brackets. Something like this:
include('elephpant.php');

$ele = new Elephpant();

// call the dance method
$ele->dance();
Look back at the class declaration for Elephpant and you'll see the dance method actually echoes from within it. Indeed when we run the code example here, we see "elephpant dances!" as our output. It is a very trivial example but I hope it does show how to call methods against our objects. An alternative approach (and probably a better one within an actual application) would be to create the string and use it as the return value for the function. Then the calling code can take the string and echo it, or do whatever else it needs to, in a more flexible way.

Inheritance

Now we know how to create and interact with objects, let's step things up a bit and look at how we can create objects which are similar in some ways and different in others, using inheritance. If you are accustomed to OOP from any other programming languages then this will seem very familiar to you, so here is a quick look at how this can be done in PHP. We already have our Elephpant class declared, so let's add a Penguin class as well. They will both inherit from the parent class Animal, which looks like this:
class Animal{

    public $type = "animal";

    public function dance() {
        echo $this->type . " dances!\n";
        return true;
    }
}
animal.php
The animal has a "type" property, and a dance() method. It uses the type property in the dance() method to create the output, using $this to refer to the current object. In PHP, $this is a special keyword which refers to the current object from within its own class.
Now we can create a Penguin class that inherits from this general Animal class, by using the extends keyword to denote its parent:
class Penguin extends Animal {
    public $type = "penguin";
}
penguin.php
The penguin class would inherit the type property set to "animal" if we didn't override it by setting the property again in this class. However even without declaring a dance() method, the penguin can dance!
include('animal.php');
include('penguin.php');

$tux = new Penguin();

// make tux dance
$tux->dance();
The above example gives the output "penguin dances!" – using the dance() method from the Animal class, which is available because the Penguin class extends it, and the type property set separately in the Penguin class itself.

Access Modifiers

Take a look at the previous example. The type is set in the class, but we could easily set it from our main code if we wanted to. Imagine if we put $tux->type = "giraffe" before we asked him to dance! Sometimes this is the desired behaviour, and sometimes it isn't. To allow us to control whether properties can be changed outside a class, PHP gives us access modifiers. An example of these are the "public" keywords you see in the classes shown above. To prevent the type property being edited from outside the class, we can declare the Penguin type to be private, so the class now looks like this:
class Penguin extends Animal {
    private $type = "penguin";
}
private_penguin.php
The following code listing shows us trying to set the now-private type property, and is followed by the resulting output.
include('animal.php');
include('private_penguin.php');

$tux = new Penguin();

// change the type
$tux->type = "linux penguin";
// make tux dance
$tux->dance();

Fatal error: Access level to Penguin::$type must be public (as in class Animal) in /home/lorna/.../OOP/private_penguin.php on line 5
The resulting message feeds back to the user that the type property can't be modified, and even includes the detail that the property was public in the parent class. Access modifiers are pretty powerful, we should look at them in more detail.
Access modifiers can be applied to properties and to methods and to properties. The options are public, private and protected. In PHP4, these weren't available and everything is public. As a result, and to maintain backwards compatibility, if an access modifier isn't specified then the property or method defaults to being public. This isn't recommended practice however, and it is best to be explicit about which is intended.
Public: The public access modifier means that properties and methods can be accessed from anywhere, within the scope of the object itself, and also from outside code operating on an object.
Private: The method or property is only available from within the scope of this specific class. Before using this option, read on to find out about the "protected" access modifier.
Protected: The method or property is available from within this class, and from within any classes with extend or implement this class. This is ideal where you don't want external code to change the class, but you do want to be able to extend the class later and take advantage of this property or method. Protected is more flexible than private and almost always the better choice.
Using these access modifiers we can control where our class methods and properties can be accessed from. We looked at an example of properties and this works in the same way for method calls – they cannot be accessed from outside of the class definition unless they are declared to be public. It can be very useful indeed to declare methods as protected, where they are internal helper methods used by other class methods but not intended to be accessed directly. In PHP4 there was no support for this and so the internal methods were sometimes named with an underscore to hint that this was their intended use – it is still possible to see this naming convention in use today, although it is not needed.