Back To Class

Learn about classes, constructors and extensibility in PHP 4.0.

OOPs!

If you've been programming for a while, you've probably heard the term OOP before - it stands for Object-Oriented Programming, and refers to a technique in which you create program "objects" and then use these objects to build the functionality you need into your program. And maybe you've wondered just how useful this is, and how you could go about adding this capability to your own code.

Well, wonder no more. Your prayers have been answered.

Over the next few pages, this article is going to take a look at OOP in PHP4, with an explanation of PHP4 classes and a few examples of how you could use them.

Who Needs Class, Anyway?

Before beginning, though, let's make sure that you have a clear idea of the concepts involved here.

In PHP, a "class" is simply a set of program statements which perform a specific task. A typical class definition contains both variables and functions, and serves as the template from which to spawn specific instances of that class.

Specific instances of a class are referred to as "objects". Every object has certain characteristics, or "properties", and certain pre-defined functions, or "methods". These properties and methods of the object correspond directly with the variables and functions within the class definition.

Once a class has been defined, PHP allows you to spawn as many instances of the class as you like. Each of these instances is a completely independent object, with its own properties and methods, and can thus be manipulated independently of other objects.

Now, you're probably wondering whether this is a little redundant, since PHP also allows you to create your own functions and use them wherever required in your code. And you're correct, to some extent - if you're only planning to spawn a single object, a class is redundant and a function will work just as well.

But there are situations where you need to spawn more than one instance of an object - for example, two simultaneous database links for two simultaneous queries, or two shopping carts. In such a situation, classes are preferred, since each instance of the class comes with its own variables and functions, and thus can be manipulated without affecting other variables within the program.

Classes also help you keep your code modular - you can define a class in a separate file, and include that file only in the pages where you plan to use the class - and simplify code changes, since you only need to edit a single file to add new functionality to all your spawned objects.

Driving Around The Bend

Let's consider a simple example, which will illustrate this better.

Take your average everyday car, that four-wheeled gasoline-chugging monster that you drive to work every day. Can you consider it, within the framework of OOP, as an "object"?

Why not? After all, every car has certain characteristics - the colour, the shape, the number of doors, the hood ornament - which are equivalent to object properties. And every car comes with certain obvious functions as well - start, stop, turn, accelerate, decelerate - all of which are equivalent to object methods.

Let's take it a little further. Every car can, in fact, be considered a subset of the class Automobile, which defines the basic characteristics and functions of every automobile on the planet. Once the class Automobile spawns a new car, or "object", its individual characteristics (color, shape) can be adjusted independent of other objects.

Now, if you sat down to code this class, it would probably look something like this:

<?php

class Automobile
{

    // this is where the properties are defined

    var $colour;
    var $shape;
    var $size;
    var $number_of_doors;
    var $number_of_seats;

    // this is where the functions are defined

    function start()
    {
    // code goes here
    }

    function stop()
    {
    // code goes here
    }

    function accelerate($speed)
    {
    // code goes here
    }

    function decelerate($speed)
    {
    // code goes here
    }

}

?>

If Wishes Were Prancing Horses...

Given the class, it's now simple to spawn as many Automobiles as you like, and adjust the individual properties of each. Take a look:

<?php
// let's spawn a couple of cars

// this is mine...
$his = new Automobile;
$his->make = "Ferrari";
$his->colour = "Black";
$his->shape = "Cigar";

// ...and this is yours
$hers = new Automobile;
$hers->make = "Porsche";
$hers->colour = "Silver";
$hers->shape = "Torpedo";

// hey...i can dream, can't i

// i feel like taking mine out for a spin
$his->start();

// speed limit? you must be joking!
$his->accelerate(180);

// joining me, are you?
$hers->start();
$hers->accelerate(150);

// oops...was that a speed trap?
$his->decelerate(80);
$hers->decelerate(80);

// busted!
$his->stop();
$hers->stop();

?>

As the illustration above shows, once new objects are defined, their individual methods and variables can be accessed and modified independent of each other. This comes in very handy, as the next few pages will show.

New Cars For Old

Now that you've got the concepts straight, let's take a look at the nitty-gritty of a class definition.

<?php

class Automobile
{
    // this is where the properties are defined

    var $colour;
    var $shape;
    ...

    // this is where the functions are defined

    function start()
    {
    // code goes here
    }
    ...
}

?>

Every class definition begins with the keyword "class", followed by a class name. You can give your class any name that strikes your fancy, so long as it doesn't collide with a reserved PHP word. A pair of curly braces encloses all class variables and functions, which are written as you would normally code them.

In order to create a new instance of a class, you need to use the "new" keyword, and assign the newly-created object to a PHP variable.

<?php

$his = new Automobile;

?>

In English, the above would mean "create a new object of class Automobile and assign it to the variable $his".

You can now access all the methods and properties of the class via this variable.

<?php

// accessing properties
$his->make = "Ferrari";
$his->colour = "Black";

// accessing methods
$his->start();
$his->accelerate(180);

?>

Again, in English,

$his->make = "Ferrari";

would mean

"assign the value Ferrari to the variable $make of this specific instance of the class Automobile", while

$his->accelerate(180);

would mean

"execute the function accelerate() with parameter 180 of this specific instance of the class Automobile".

Note the -> symbol, and the fact that the $ symbol is omitted when accessing variables of a specific class instance.

Ford's Law

In case you need to access functions or modify variables within the class definition itself, PHP offers the $this keyword, which is used to refer to "this" class. For example, if you were to add Henry Ford's edict of "any colour, so long as it's black" to the definition above, you'd end up with something like this:

class Automobile
{
    // this is where the properties are defined

    var $colour;
    var $shape;
    ...

    // this is where the functions are defined

    function start()
    {
    // code goes here
    }

    function turnColourBlack()
    {
    $this->colour = "Black";
    }
    ...
}

In this case, the $this prefix indicates that the variable to be modified is included within the current class definition - or, in English, "change the value of the variable $colour within this class to Black". The $this prefix thus provides a convenient way to access variables and functions which are "local" to the class.

Turning The Tables

Let's take a look at an example which illustrates how useful classes can actually be. This next class definition allows you to specify the number of rows and columns you would like, and then creates an HTML table for you on the basis of your selections.

<?php

class Table
{

    // set the rows and columns
    function setGrid($rows, $columns)
    {
    $this->rows = $rows;
    $this->columns = $columns;
    }

    // set the colours and fonts
    function setInterface($bcolor, $fcolor, $font)
    {
    $this->bcolor = $bcolor;
    $this->fcolor = $fcolor;
    $this->font = $font;
    }

    // draw the table
    function drawTable()
    {
    echo "<table border=1 bgcolor=" . $this->bcolor . ">";

    for ($x=1; $x<=$this->rows;$x++)
        {
        echo "<tr>";

        for ($y=1; $y<=$this->columns;$y++)
            {
            echo "<td><font face=\"" . $this->font . "\" color=" . $this->fcolor .
">" . $x . ", " . $y . "</font></td>";
            }

        echo "</tr>";

        }

        echo "</table>";

    }

}

?>

If you take a close look, you'll see that this class contains three functions - one to set the number of rows and columns, one to decide the foreground and background colours and the font, and one to actually draw the table. Note the frequent usage of the $this keyword to reference local variables within the class.

Now, to use this, all you need to do is include this class definition (which you could save to a separate file named "tables.inc") within your PHP script.

<?php

// this is a PHP page which will contain many tables

// include the class definition
include("tables.inc");

?>
<html>
<head>
<basefont face=Arial>
</head>
<body>

Here is the first table.

<?php

// first table
$alpha = new Table;
$alpha->setGrid(4,4);
$alpha->setInterface("green", "white", "Arial");
$alpha->drawTable();

?>

<p>
And here's the second.

<?php

// second table
$beta = new Table;
$beta->setGrid(1,9);
$beta->setInterface("blue", "white", "Arial Black");
$beta->drawTable();

?>

<p>
Third and fourth go together.

<?php

// third table
$gamma = new Table;
$gamma->setGrid(2,4);
$gamma->setInterface("black", "white", "Verdana");
$gamma->drawTable();

// fourth table
$omega = new Table;
$omega->setGrid(4,2);
$omega->setInterface("white", "black", "Trebuchet MS");
$omega->drawTable();

?>

</body>
</html>

Pretty cool, huh?

Under Construction

It's also possible to automatically execute a function when the class is called to create a new object. This is referred to in geek lingo as a "constructor" and, in order to use it, your class definition must contain a function with the same name as the class.

For example, if you'd like your car to start automatically when you create it, add the function Automobile() to your definition, as show below.

<?php

class Automobile
{

    // constructor
    function Automobile
    {
    $this->start();
    }

    function start()
    (
    // code goes here
    )

}

?>

Or, in the table example you just saw, you could define a default grid and colours for your table when the object is created.

<?php

class Table
{

    // constructor
    function Table()
    {
    $this->rows = 4;
    $this->columns = 5;
    $this->bcolor = "black";
    $this->fcolor = "white";
    $this->font = "Times New Roman";
    }

    // other functions

?>

And now, when you create a new Table object like this, without defining any parameters,

<?php

// first table
$alpha = new Table;
$alpha->drawTable();

?>

you'll get a default 4x4 black and white grid. Try it and see for yourself!

Extending Yourself

Two of the best things about OOP are extensibility and inheritance. Very simply, this means that you can create a new class based on an existing class, add new features (read properties and methods) to it, and then create objects based on this new class. These objects will contain all the features of the original parent class, together with the new features of the child class.

As an illustration, consider the following evenBetterTable class, which adds support for cell spacing and borders.

<?php

class Table
{

// constructor
function Table()
{
$this->rows = 4;
$this->columns = 5;
$this->bcolor = "black";
$this->fcolor = "white";
$this->font = "Times New Roman";
$this->spacing = 0;
$this->bsize = 0;
}

// set the rows and columns
function setGrid($rows, $columns)
{
$this->rows = $rows;
$this->columns = $columns;
}

// set the colours and fonts
function setInterface($bcolor, $fcolor, $font)
{
$this->bcolor = $bcolor;
$this->fcolor = $fcolor;
$this->font = $font;
}

// draw the table
function drawTable()
{
echo "<table cellspacing=" . $this->spacing . " border=" . $this->bsize .
" bgcolor=" . $this->bcolor . ">";

for ($x=1; $x<=$this->rows;$x++)
{
echo "<tr>";

for ($y=1; $y<=$this->columns;$y++)
{
echo "<td><font face=\"" . $this->font . "\" color=" . $this->fcolor .
">" . $x . ", " . $y . "</font></td>";
}

echo "</tr>";

}

echo "</table>";

}

}

class evenBetterTable extends Table
{

// constructor
function evenBetterTable()
{
$this->rows = 4;
$this->columns = 5;
$this->bcolor = "black";
$this->fcolor = "white";
$this->font = "Times New Roman";
$this->spacing = 0;
$this->bsize = 0;
}

// set cell spacing
function setSpacing($space)
{
$this->spacing = $space;
}

// set borders
function setBorder($size)
{
$this->bsize = $size;
}

}

?>

The "extends" keyword is used to extend a parent class to a child class. All the functions and variables of the parent class immediately become available to the child class.

Note how the constructor has been repeated in the evenBetterTable class - this is because when you call a child class, the parent class' constructor is not called automatically.

And here's how you could use it:

<?php

// this is a PHP page which demonstrates extensibility and inheritance

// include the class definition
include("tables.inc");

?>
<html>
<head>
<basefont face=Arial>
</head>
<body>

<?php

// first table
$alpha = new evenBetterTable;
$alpha->setGrid(4,4);
$alpha->setInterface("yellow", "black", "Arial Black");
$alpha->setSpacing(10);
$alpha->setBorder(2);
$alpha->drawTable();

?>

</body>
</html>

Be My Guest

And finally, here's another, slightly more complex example which demonstrates how powerful classes can be. It's a Guestbook class, and it includes support for most of the common functions available in a guestbook.

Now, how do you use it? Well, first you need a form like this, which serves as the data entry page for the guestbook.

<html>

<head>
<title>Sign My Guestbook</title>
</head>

<body>

<form action="book.php4" method="post">
<center>
<table width="600" cellpadding="10" cellspacing="5" >

<tr>
<td width="300" align="right">Name</td>
<td width="300" align="left"><input type="text" name="name" size="25"
maxlength="25"></td>
</tr>

<tr align="center">
<td width="300" align="right">Email Address</td>
<td width="300" align="left"><input type="text" name="email" size="25" ></td>
</tr>

<tr>
<td align="right" width="300">Comments</td>
<td align="left" width="300"><textarea name="comments" cols="25" rows="3"
wrap="virtual"></textarea></td>
</tr>

<tr>
<td align="center" colspan=2 width="600"><input type="submit"  value="Sign
my guestbook"></td>
</tr>

</table>
</center>
</form>

</body>
</html>

As you can see, the form data will be submitted to a PHP script called "book.php4" - let's take a look at that next.

<?php

// this is book.php4 - it accepts form data and writes to a file

// Guestbook class included
include("guestbook.inc");

// spawn a guestbook
$mybook = new Guestbook();

// set an object property
// make sure you have permission to write this file
$mybook->usefile('melonfire.dat');

// use a method of the new object to write data
if($name && $email && $comments)
    {
    $mybook->add_entry($name,$email,$comments);
    }

// object also includes a method to display previous entries
$mybook->display();

?>

This script creates a new Guestbook object, specifies the file to use for the data, and then adds an entry to it. Once that's done, it calls a display() function to display the entries in the book. Needless to say, all these functions have been created in the definition of the Guestbook class.

And now for the definition itself - take a look:

<?php

class Guestbook{

    // default settings
    function Guestbook()
    {
    $this->title = "My Guestbook";
    $this->fontface = "Verdana";
    $this->fontsize = "2";
    $this->fontcolor = "#FF0000";
    $this->filename = "default.txt";
    }

    //set the title
    function set_title($title)
    {
    $this->title = $title;
    }

    //set the font properties
    function set_fontsize($fontsize)
    {
    $this->fontsize = $fontsize;
    }

    function set_fontface($fontface)
        {
    $this->fontface = $fontface;
        }

    function set_fontcolor($fontcolor)
    {
    $this->fontcolor = $fontcolor;
    }

    // set the name of the data file
    function usefile($file)
    {
    $this->filename = $file;
    }

    // function to actually write form data to file
    // elements of each entry are separated by a |
    function add_entry($name,$email,$comments)
        {
    $entry = $name."|".$email."|".$comments."\n";
    $this->fpointer = fopen($this->filename,"a+");
    fputs($this->fpointer,$entry);
    fclose($this->fpointer);
        }

    // split entries against |
    // and call display_entries() function
        function split_entries($file)
        {
    $entries = file($file,"r");
    for($counter = 0; $counter < sizeof($entries); $counter++)
        {
        $entry = explode ("|", $entries[$counter]);
        $this->display_entries($entry);
        }
        }

    // display an entry in the guestbook
        function display_entries($entry)
        {
    for($counter = 0;$counter < sizeof($entry);$counter++)
        {
        print "<center><font face=\"$this->fontface\" size=$this->fontsize
color=$this->fontcolor>$entry[$counter]</font></center><br>";
        }
    print "<hr width=50%>";
    }

    // display the title
        function display_title()
        {
    print "<center><font face=\"$this->fontface\" size=$this->fontsize
color=$this->fontcolor>$this->title</font></center><br><hr width=75%>";
        }

    // display page
        function display()
        {
    $this->display_title();
    $this->split_entries($this->filename);
        }

}

?>

As you can see, the definition includes functions to control the interface of the guestbook, in addition to functions to read and write data. If you ever decide to go into the guestbook services business, you'd probably offer your users something quite similar in order to allow them to add guestbook services to their Web site (as many of the free Web space providers out there already do).

And that just about covers classes and objects in PHP. See you soon!

Note: All examples in this article have been tested on Linux/i586 with Apache 1.3.12 and PHP 4.0. Examples are illustrative only, and are not meant for a production environment. YMMV!

This article was first published on26 Sep 2000.