Skip to page content or Skip to Accesskey List.

Work

Main Page Content

Php Intro To Objects And Classes

Rated 4.1 (Ratings: 9)

Want more?

  • More articles in Code
 

Tony Light

Member info

User since: 09 Jul 2002

Articles written: 1

PHP's Object Oriented capabilities may not be complete, but the benefits of

convenience and code re-use from using Objects and Classes are here now. If

you are already dabbling in PHP, but haven't yet checked out Classes, have a

look at this simple (yet useful) example of an Error Message Class.

Beginners Guide to Object Oriented Terminology

When I first came across OOP, the terminology served as a barrier - partly

because the people explaining it were trying to stress what is different about

OOP, rather than saying what is the same. I was a tad disappointed when I discovered

that OOP was mainly a way of packaging existing good ideas and practices, but

cheered up when it transpired that a lot of languages now include OOP constructs

that make it much easier to code in this way.

There are four terms that you should feel comfortable with: Class, Object,

Property and Method.

A Class is a blueprint for creating an Object. It tells you what variables

(a.k.a. Properties) the Object can have, and what functions (a.k.a. Methods)

can be used to manipulate the Object's Properties.

None the wiser? I don't pretend that the previous couple of sentences constitute

a proper definition of anything - but it was definitions that created the barrier

for me when I first looked at OOP. Don't get hung up on it - take a look at

this non-computing example:

A Real-World Example

Consider an old-fashioned radio, with an on/off switch, and a tuning dial.

The Class is the circuit diagram and assembly instructions that enable the

worker to build the radio, and also the User Manual.

Each and every such radio built is an Object.

The methods would be something like:

Build Radio ( )

Turn Radio On ( )

Turn Radio Off ( )

Tune Radio ( )

The Properties might be:

serial_number - to uniquely identify the radio.

status - whether the radio is currently on or off.

current frequency - to which the radio is tuned.

Every Object has the same methods available. Every Object has values for the

same Properties - but these values may be different. Indeed in our radio example,

the serial number should always be different.

Still none the wiser? Well try working through the following example, and see

if things click into place.

A Problem to Solve

If you have any complexity at all in your PHP pages, then you will most likely

have run into this irritating little scenario: You have just found a database

error perhaps, or a user input error, but you cannot immediately output an error

message. What do you do? Set a flag and check it later on when you are ready

to show the error message? OK, that should work. Might get a bit messy if you

find a lot of errors. You could stick all the error messages in an array, then

print out the array when you are ready. Yeah, that sounds good. Lets do that

- but lets do it using a Class, which we will call ErrorMessages.

So What Does This Class Need to Look Like?

Well what do we want to do with it? Let me suggest the following:

We want to be able to identify errors and store error messages for outputting

later, when we are ready.

We might have different types of errors - e.g. System errors such as unavailable

databases, or User errors such as invalid data put in input fields on forms.

It would be nice to report these separately.

The output should fit in with the look and feel of the rest of the website.

No doubt you are already concocting more complicated requirements, but lets

leave it at that for the purposes of this article. What you do in the privacy

of your own room is up to you.

Right then. That doesn't look too complicated. Seems to me like we want three

Methods here. One to create a bucket which we can keep error messages in. Another

to drop an error message into the bucket, and a final one to tip all the error

messages out of the bucket and onto the screen.

I'm anticipating output that will look something like this:

*** System Errors ***

1. Missing Table - could not locate database table 'awol'.

2. Database error - no such column 'fifth' in table 'usa'.

If we stick a few [CSS] class names in the HTML tags that we output, then we

should be able to use a stylesheet to format the output to fit in with whatever

site we use it on.

The Class Framework

It ain't obligatory, but most PHP developers put their classes in separate

files that they can include in whichever pages it is needed. You can put as

many Classes as you like inside one include file, but for this example we will

just have the one.

OK - so create a new file to use as an include: say error_class.inc.

Open the include file and type in:

<?php

class ErrorMessages

{

}

?>

This is just the framework that tells PHP that it is dealing with a Class definition.

Now we need to tell PHP what the variables are that we may choose to populate

for each Object. Now what was it that they were called again? Properties. OK,

between the curly wurlies, add this:

var $errorMsgBlockLabel;

var $errorCount;

var $errorMsg;

$errorMsgBlockLabel is the 'title' that we will show on the screen above the

errors that have occured.

$errorCount is just going to keep track of the number of errors.

$errorMsg is going to be an array of errors that have occured. Each array element

will itself be an array (containing a label and a message) but we don't need

to be that specific at this stage.

The Constructor

We now need to add the only Method that a Class MUST have. It has the same

name as the Class itself (in this case ErrorMessages) and is refered to as the

'Constructor'. This Method will do whatever is necessary to create a new instance

of an ErrorMessages Object.

So what do we need to do to create our new Object? Not a lot, really. We need

to give it a 'title' (i.e. specify a value for $errorMsgBlockLabel) and initialise

the $errorCount to 0.

OK - so after your var definitions, before the final curlie wurlie, insert

this Constructor function:

function ErrorMessages($x)

{

$this->errorCount = 0;

$this->errorMsgBlockLabel = $x;

}

$x, rather obviously, is the 'title' string, which we will pass when we request

a new ErrorMessages Object.

$this

Whats all this $this->errorCount business?

In normal PHP you would refer to a variable as something like $errorCount,

and a function as something like addError($label,$message).

When we are dealing with Properties and Methods we must use a slightly different

notation. e.g. $SysErrs->errorCount and $SysErrs->addError($label,$message)

where $SysErrs is the name of the Object that we are interested in.

Inside the Class definition we have absolutely no idea what the Objects based

on this Class are going to be called, so we use the special pseudo-variable

$this to mean the current Object. It just allows us to use a similar notation

inside and outside the Class definition.

The exception to this object name->method name( ) rule

is the Constructor. When we want to create a new Object we use the following

syntax:

object name = new class name&(params)

e.g. $UserErrs = new ErrorMessages("User Bloopers");

Can't wait to use your class?

Create a php file - say 'error_class_test.php'. I'll assume you create it in

the same directory as the include file. Type this in:

<?php

include ("error_class.inc");

$UserErrs = new ErrorMessages("User Bloopers");

echo ("<P>We have $UserErrs->errorCount user errors</P>");

?>

Load up both files to your webserver, then run the php file. It should just

say "We have 0 user errors".

Not very exciting, but as it stands that is the limit of our Classes functionality.

Lets change that.

Now some Methods

First, a method to add an error message. Immediately after the Constructor,

before the last curlie wurlie, add this:

function addError($label, $message)

{

$this->errorCount ++;

$this->errorMsg[$this->errorCount]["label"] = $label;

$this->errorMsg[$this->errorCount]["message"] = $message;

}

This Method increments the errorCount, then creates an element errorMsg[n]

where [n] is the current errorCount. This element is itself an associative array

("label" => $label , "message" => $message).

Now we can add an error, e.g.

$UserErrs->addError("Dodgy Input","This does not appear

to be a valid email address");

and we could even show that error using something like print_r - but even if

we remembered to put <pre></pre> tags around it, that

would still look naff. No, we definitely need a Method to output these error

messages in a decent format. So add this immediately before the last curlie

wurlie:

function showErrors()

{

if ($this->errorCount >0) {

?>

<div class="errorblock">

<span class="errorblocklabel"><?php echo $this->errorMsgBlockLabel ?></span>

<?php

for ( $i = 1; $i <= $this->errorCount; $i++ ) {

?>

<p>

<span class="errornumber"><?php echo "$i:"?></span>

<span class="errorlabel"><?php echo $this->errorMsg[$i]["label"] . " - " ?></span>

<span class="errormessage"><?php echo $this->errorMsg[$i]["message"] ?></span>

</p>

<?php

}

?>

</div>

<?php

}

}

Nothing too tricky here. The if statement ensures we only get any output

if we have any errors. Then we print out the label for the block of errors,

and then loop through each error.

To test it, you can add a couple of lines to your php file, so it looks like

this:

 

<?php

include ("error_class.inc");

$UserErrs = new ErrorMessages("User Bloopers");

$UserErrs->addError("Invalid Input","This does not appear to be a valid email address");

$UserErrs->addError("Careless","You appear to have forgotten something.");

$UserErrs->showErrors();

echo ("<P>We have $UserErrs->errorCount user errors</P>");

?>

Eye Candy

OK so far? But it doesn't look very nice. We could just put a bit of formatting

into the showErrors() function - but being a CSS fan, I reckon its better to

use styles. I'm not going to explain it, 'cos this article is about Classes

not CSS.

Stick the following stylesheet in (right at the start of your php file, before

the opening php tag). It should really go in the <head> section - but

if you've been following the instructions you won't have one!

<style type="text/css">

.errorblock {

border: 1px solid #900 ;

margin-bottom: 5px;

margin-top: 5px;

font-size: 10pts;

background: #fee;

}

.errornumber {

background: #fff;

color: #900;

padding-left: 3px;

padding-right: 1px;

border: 1px solid #900 ;

}

.errorlabel {

font-weight: bold;

color: #900;

padding-left: 3px;

}

.errormessage {

color: #090;

}

.errorblock p {

display: block;

padding: 3px;

margin-bottom: 0;

margin-top: 0;

padding-top: 2px;

padding-bottom: 2px;

}

.errorblocklabel {

display: block;

padding: 3px;

background: #900;

font-weight: bold;

font-size: 12pts;

color: #fff;

}

</style>

Did I mention Re-usability?

Well if I didn't, shame on me. I'm certainly not going to claim that Classes

are the only way of writing reusable code - but they certainly make it an attractive

proposition.

Suppose we might encounter System errors and/or User Errors while running our

PHP code. We might not want to lump all our errors in together. No problem.

Instead of just creating one ErrorMessages Object, we can create as many as

we want (but two will do for us).

Add a few extra lines to the php part of your .php page, so it looks like this:

<style type="text/css">

... snip ...

</style>

<?php

include ("error_class.inc");

$UserErrs = new ErrorMessages("User Bloopers");

$SysErrs = new ErrorMessages("*** System Errors ***");

$UserErrs->addError("Invalid Input","This does not appear to be a valid email address");

$UserErrs->addError("Careless","You appear to have forgotten something.");

$SysErrs->addError("Missing Table","could not locate database table 'awol'");

$SysErrs->addError("Database error","no such column 'fifth' in table 'usa'.");

$UserErrs->showErrors();

$SysErrs->showErrors();

echo ("<P>We have $UserErrs->errorCount user errors</P>");

echo ("<P>We have $SysErrs->errorCount system errors</P>");

?>

Stick that on your server and give it a whirl.

Neat?

But the real re-use comes when you use the Class in another project. All you

need to do is copy the Class definition include file and include it wherever

you need it.

Using our Objects within Functions and other Objects

Right then, but what if you already have lots of functions or even other Classes,

within which you might generate error messages? Can you still use the ErrorMessages

Class?

Of course. The Object you create can be treated much like a variable. If you

want to use it in a function (or Method in another Class) you can declare it

as global. Note that it is the Object not the Class that is declared as global

- so you must know its name. e.g.

function fooBar() {

global $SysErrs;

... do something that goes wrong ...

if (error has occured) {

$SysErrs->addError("Woopsie","Function fooBar failed");

}

}

But what would happen if you hadn't already created the $SysErrs Object? You

would get an error. Ironic really.

What can you do about it? Test for the existence of the Object. If it exists,

fine. If not, handle it some other way - maybe by creating the object - but

you can only do that if the Class definition itself exists.

So we have a few conditions to test for before we know exactly how we are going

to deal with our error. How you deal with each failure depends on your situation,

and the anticipated situations where your code might be used. So I'll just give

you the syntax for checking whether the ErrorMessages Class exists:

if (class_exists("ErrorMessages")) { ..... }

and for checking if the Object $SysErrs exists:

if($SysErrs) { ..... }

If the Class doesn't exist, then you could include the Class definition file

- as long as you are sure where it is!

If the Object doesn't exist, then you could create it, or you could cop out

and handle the error some other way.

Of course - if you create an ErrorMessages Object, you would be wasting your

time if the showErrors() method was never called for that Object. Crikey, in

my crystal ball I can see a routine that looks through all the Objects in your

script, and calls showErrors() for every Object with a Class of ErrorMessages.

Stop now, I've woffled enough.

Possible advantages of Classes over Procedural Code

Treading very carefully now, as some folks seem awfully touchy about this.

The scribblings that follow are definitely IMHO. So please don't give me a kicking.

And if you must give me a kicking, then please, not the face - not the face!

Nothing in this example could not be done with a set of functions in an include

file. Hey, it is an easy example, because it gets hard to write articles when

the examples are big and complex.

Quite probably, even with big, complex Classes, you could still do everything

with a set of functions instead.

So why do I like Classes?

Keeping variables as Object Properties saves you from having to use global

variables. Good for security. It also avoids accidentally using the same variable

across two different sets of functions.

All Object Properties are available to all functions (a.k.a. Methods) within

the Class. So you are not having to specify lots of variables as global within

each function, or pass them in as parameters.

Class definitions make me keep everything to do with the Class in one place.

With collections of functions it is easier to write code that is harder to maintain.

Just thinking in terms of Classes, Properties and Methods seems to help get

my mind around the problem.

If you are using Sessions, by registering the Object with the Session, all

the Object's Properties are automatically serialized, stored in the session

and then unserialized for you on the next page. Handy.

Want to know more?

Here is a list of useful links.

Enjoy.

Feeling Lazy?

Personally, I often get benefit from actually typing things in - particularly

when dealing with some new notation such as that used by PHP for classes and

objects. If that doesn't float your boat, here is a zip

file
with the class definition and the test page.

Even less effort would be to look at the demo

page.

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.org Evolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.