Published on 2006-12-04 by John Collins. Socials: YouTube - X - Spotify - Amazon Music - Apple Podcast |
PHP is a wonderfully user-friendly programming language. It allows developers who do not come from a formal computer science background to start to develop server-side web application code with some ease, especially when compared with competing technologies like Ruby, C#.NET or Java, which tend to have a steeper learning curve.
One of the main reasons for this steeper curve is that these languages basically force you to program using object oriented (OO) methodologies. For someone without a degree in computer science who has not sat through numerous lectures on OO design and the UML, all of these new terms and techniques can seem off putting at best.
PHP does not enforce OO like these other languages, but it does support it. In fact with the release of PHP 5 the support of OO design in PHP has greatly increased, putting PHP on a par with Java in terms of the object oriented functionality it offers, without the constraints that strictly-OO languages force upon you.
In this article we will examine OO from the perspective of someone who has developed web pages and forms with PHP before, but who has never used classes and objects in the language. We will look at the benefits of OO design by firstly explaining the problems that OO was designed to address, and some sample code in PHP 5 will also be presented.
Before we begin, we will lay the foundations of the example that we will use throughout this example. Our example is based on the common ideas of a typical shopping cart system. Like most web applications, a shopping cart system will have the concept of a person in there someone, to represent customers, employees, and system administrators alike. A shopping cart system would be pretty useless without a cart, so we will have one of those in there to.
Most applications are just variations of CRUD (Create Read Update Delete) transactions. Your website is essentially an elaborate frontend on the database backend, with your PHP code acting as a go-between by taking user input from the website and generating appropriate CRUD transactions for the database.
Take our person: we need to create new user accounts, read in details about the user from the database, update them so that a person can change their details, and finally allow a system administrator to delete a person's account if required.
Using traditional structured approached, we might have a separate file for each of these major transactions. Each file would have all of the functionality required for that transaction embedded within the file, for example the "Edit Your Account" page would have an SQL UPDATE query for the database, and the "Create New Account" page would have an INSERT query and so on. To allow for some level of reuse, you might put common code into external PHP files in functions, and include these files whenever you need to use that function.
The design approach described is fine and will work for 90% of simple applications. However sometimes you might want to reuse the same functionality across different pages, and associate the same attributes and functions to each logical element in your system. Classes and objects will help you to achieve this.
Take our person. At the simplest level, the person will have the following attributes:
username
password
This is the bare minimum to allow your person to be able to log in. Now we might define a functions like this:
logon(username, password)
The function accepts a username and password, say from a web form, and then queries the database for the user and sees if the password provided matches the one in the database.
A class is a template for a user, and defines all of the attributes and methods that we want to associate with the person class. An object is an example of a class in memory, in effect an instantiation of the class template. While we will only have one person class defined in a PHP file, we can have many objects belonging to that class in memory at any given time.
<?php class Person { // attributes public $username; public $password; // special function that is called whenever the object is created function __construct($username, $password) { $this->username = $username; $this->password = $password; } // methods public function logon($username, $password) { // do the logon code... } } ?>
Classes and objects allow us to encapsulate all of the attributes and functions associated with our system elements into one definition, which will be stored in one file and included wherever we need to work with the person class. Encapsulation represents one of the main benefits of OO design.
Now that we have our (very basic!) person class designed, we decide that there will be another kind of person using the system: an administrator. The administrator will have the same attributes and abilities as a regular person, with the addition of a new function for deleting other users from the system.
Great, now we have our two classes defined, but you can see the problem we now have: code duplication. We want to avoid code duplication because it gives us multiple versions of the same functions to maintain, basically giving us more work! Inheritance will allow us to remove the code duplication. It works by allowing us to extend one class to create another. If we extend the parent person class with the child administrator class we end up with this:
What this means is that the administrator class will inherit the username and password attributes from the parent class, as well as the logon function. The beauty of inheritance is that it is one way: the person class will not have access to the specialized delete_user function, which is great because we only want administrators to have that functionality. Here is the new class in code, notice the use of the extends keyword:
<?php // include the definition of the Person class so that we can extend it require_once 'Person.php'; class Administrator extends Person { // special function that is called whenever the object is created function __construct($username, $password) { $this->username = $username; $this->password = $password; } public function delete_user($username) { // the delete user code goes here... } } ?>
You might be wondering at this stage, especially if you are coming from a PHP 4 background, why we are using the keyword public in front of each attribute and function defined in the two classes. This keyword sets the visibility of the attribute or function in terms of inheritance and other code attempting to access the objects of the class. There are three options:
In PHP 4 all attributes and functions are public so no level of protection is on offer, the visibility controls offered in PHP 5 mimic those in languages like Java and represent a major improvement.
Getting back to our fledgling OO system, we now need to define a new class for the cart:
Here we have defined a Cart with an owner (which will be a username from the Person class), an array of items to hold the actual shopping cart contents, and some new functions for adding and removing items from the cart.
The next step is to add in some methods for loading and saving our objects to the database (remember the CRUD transactions?). At first we might be tempted to do the following, but of course this will introduce more duplication:
Instead we will take the common code from the classes and create a new parent class, this process is called generalization. Here is the revised diagram:
In general when we are saving objects to a database, where each row in a table will represent an object, we will add a special attribute called id. Id is usually just an auto number assigned by the database, which will act as a unique identifier for that object.
Now that our simple model is complete, how do we actually go about using these classes? Well if we wanted to create a new Administrator object called John and save it, here is the code to do it:
<?php // Include the class we want to use here. // Note that we would include any parent classes used by Administrator in the // Administrator.php file require_once 'Administrator.php'; // firstly create the new object $John = new Administrator("john","password"); // ...and save it! $John->save(); ?>
Yep it really is that simple to use objects once you have done the hard work of coding the classes. Assuming that you have included all of the necessary INSERT or UPDATE queries in the save() function of the Data_Access_Object (this is just a fancy term for objects that map to database rows), then you can simply call the save() function (or method) on the $John object, safe in the knowledge that the database transaction will be carried out.
As the example in the last section highlighted, a class can be treated as a black box: you don't need to worry about the classes internal workings as long as you know that they work. In fact in a large software team, it is highly likely that you will be using classes coded by other developers, so will effectively be trusting their implementation code behind the interfaces offered by the classes they give to you.
Making the jump from regular, structured programming with static functions to OO programming with class methods is a big leap, but one that will reward you in the long run by saving you time and work. Unlike strict OO languages like Java or C#, you do not have to learn OO techniques right away to start coding PHP, but you can progress to OO later on so the learning curve is much more gradual, making PHP an ideal OO language for new programmers and experts alike.
Updated 2021 : note that the above post was originally published in 2006, but is left here for archival purposes.