by
Brian Haveri aka bwh2 | 31 December 2006This
tutorial is an introduction to object oriented programming
(OOP) with PHP. Upon finishing this tutorial, you should
have the basic tools necessary to begin navigating the world
of OOP. Throughout, we will build upon one example while key
terms and nuances to OOP with PHP are introduced. In
addition, some time will be spent showing how to integrate
object oriented PHP with MySQL.
- Creating Our First Object
- Class Variables and Visibility
- Constructor Method
- Using Arrays to Speed Up Coding
- Method Interaction
- Integrating OO PHP with MySQL
- Introducing Inheritance
- Parting Words
- Now let's get started!
Not surprisingly, object oriented programming is focused
around objects. While the idea of objects may be foreign to
you in coding terms, understanding what objects are and why
we use them shouldn't take long. In short, our
non-programming world is comprised of objects. Computers,
fish, clouds, people, and cars are all objects. Objects have
properties like color, size, name, and speed. Objects can
also be comprised of other objects: cars have doors; doors
have handles; handles have plastic levers; so on and so
forth. Objects are everywhere around us. For this reason,
many programmers find object oriented programming relatively
easy to understand.
So how do objects translate into code? If we were building a
website about users, we would create one or many user
objects. Objects are created using classes. Classes are
groups of related variables and functions. Variables hold
our object's properties like color, size, and speed.
Functions perform actions like set variable values or open
files. In this example, we could create user objects with a
User class. You can think of the User class as a template
for any user objects.
Creating an object is called instantiation
(creating an instance). Let's instantiate a user object and
code the corresponding User class:
Note: As this tutorial
progresses, code will be removed so that you don't get lost
and can focus on the task at hand. Feel free to keep or add
back code from previous examples.
Right now this user can't do anything and doesn't have any
attributes. Within classes, we use methods (aka functions)
and variables to give our objects functionality and
properties. Let's redo our first example so that our users
can have a name:
As you can see, methods are declared using
function [methodName] format, as is standard in PHP. This
simple example shows us how we can apply a name to the
object, then access the name. Continue on to learn about how
we handle variables and methods within classes.
Note about PHP versions: If you are running
PHP4, the above code will not work for you. Please continue
on to the next section for an explanation.
Within classes, we first define our
variables. In this case, our first variable is $name. A
handy feature of PHP5 (not PHP4) is increased visibility
control. Our $name variable currently has a visibility of
private. Private visibility means that the variable can only
be accessed via the methods inside the class (like setName
and getName). If we set the variable visibility to public,
our variable could be accessed externally (without the
methods). The final visibility setting for a variable is
protected, which means that variable access is limited to
parent and inherited classes, which we will discuss more
later.
In PHP4, public is the only visibility option and public
variables are declared using var instead of public. Let's
take a look at how variable visibility works by adding a
$location variable and setting it to public visibility:
So which variable visibility should you
choose? The answer is that it depends. In general, you
should be fine using private. Private is especially useful
because it supports encapsulation - the ability to hide data
and only make it accessible through a given interface. In
OOP, an interface represents the functionality given to a
particular object.
Just as we set a variable's visibility, we can also set
visibility for methods. By default, if we don't set the
visibility of our methods, they will be set to public. For
the sake of time, we will not dig into examples with
different method visibility. Continue on to learn about an
important and useful method, the constructor.
Note about $this: Within methods, we refer to class
variables and other methods using $this->. This can be seen
within the setName and getName methods. $this is a default
variable created upon instantiation and enables an object to
reference itself.
Note about naming conventions: While set[PropertyName]
and get[PropertyName] are popular method names because they
are easily understood, they are not required. You can name
these methods whatever you want.
Now is a good time to look at the constructor method. The
constructor is a method that will automatically be run when
an object is instantiated. In PHP5, we have methods called "Magic
Methods" (i.e. __construct, __destruct, and a few
others) which begin with two underscores. In PHP4, the
constructor method would be given the same name as the class
itself. So in PHP4, if we have a class named User, our
constructor method would also be named User (not
__construct). Remember, you do not need to call the
constructor method explicitly because it will be
automatically run when an instance of that class is created.
Here's a constructor in action:
Now you might be starting to see one of the benefits of
OOP - much of the code lies in the background. We could
include files containing our classes to hide the heavy duty
code even more. Because the naming conventions of classes
and methods are fairly self explanatory, we won't need to
constantly look back at our included files. Continue reading
to find out how we can use arrays to speed up our process.
Right now, it's tedious to set each property using a set
method - there must be an easier way. That's where
associative arrays combined with our constructor come in
handy. Let's create our user object and give it several
properties upon instantiation:
I have kept the set methods in case we want to change the
properties, but now the properties are established up front
via __construct. That is, we passed our $attribs array to
the object on instantiation, which in turn passed $attribs
to the constructor automatically. The advantage to using
associative arrays for this purpose is that we don't need to
explicitly set all of our variables with the methods. This
is extremely handy when integrating PHP with MySQL data,
which we will cover soon. But first, we need to learn a
little bit about method interaction and object grouping.
At this point, our methods do not interact. Let's add a
little functionality to our example by converting full state
names to the appropriate abbreviations.
In this example, we used a full state name to get its
corresponding abbreviation. We did this using a class with a
static variable. Static variables generally do not change
and can be accessed without methods. These variables act
more as reference and can be useful for things like your
database connection settings and other site wide variables.
Static variables are usually named with all capital letters.
Next, we will learn to integrate our object oriented PHP
with MySQL.
In this section, we will kill two birds with one stone.
Not only will we learn how to integrate OO PHP and MySQL,
but we will learn how to group objects. In this case, you
will create a e>UsersGroup class which will
contain an array of User objects. Each of those
User objects will be created using a row from a
MySQL query. To try this practical example, you will first
need to create a Users table in a MySQL database. I am using
a MySQL database named `kirupa_oop`. Use the queries below
to create the table and insert the sample data.
This very simple table just has two columns:
`user_id` and `user_name`. You may wish to add your own name
to this table to spice things up.
As promised, we will create a UsersGroup class. This group
will contain an array of User objects, each of which is
created using data from our MySQL table. All of my tables
are on a database named `kirupa_oop`. If your database is
not named `kirupa_oop`, you must change the database name in
the Settings class shown below. Here is our UsersGroup class
in action:
The first thing to note is that we are holding our
database connection and table name information inside our
Settings class, within static variables. In the
event that we need to change our database name, table names,
database usernames, etc. we will only do it in our
Settings class (which is preferably in a separate,
included file). Our User class is nothing new -
it only holds the name property and still receives an array
of data via __construct.
Let's look at the code for the UsersGroup class. If you
have connected to a MySQL database with PHP before, the
connection should be nothing new. The only difference is
that we use static variables for our connection settings. We
do the same for our table names because within double
quotes, our Settings class static variables cannot be
parsed. That is, just using Settings::$TABLES['tbl_users']
directly in our double-quoted SQL query will cause an error.
Our SQL query produces an array of rows, which we assign
to $result. Using a while loop, we go through our $result
array. Each element in $result is an array of values (like
id and name). Again, this should look very familiar to
anyone who has used PHP to access a MySQL database. Now
comes the OOP part: we then pass each row ($row) from our
MySQL query to our addUser method. First, the addUser method
checks if it's being passed an array of data (like $row) or
a whole User object. In this case, we are passing an array
of data. Using that array of data, addUser creates a User
object ($noob), then adds that user object to the group
array ($group).
Note about column names: When our User object is created
with array data, the constructor is looking for an array
element called name. To fulfill this request, we use a SQL
alias, which can be seen in $sql. If we did not alias
user_name AS name the $row variable would not hold an array
element called name but rather user_name. Thus, it would not
correctly populate the name variable in our User object. I
prefer to keep customization in my SQL rather than my PHP
class methods because I am more likely to reuse PHP class
methods than SQL queries. For instance, if I create a Dogs
class, I would also want a getName method and constructor.
Rather than modify several PHP methods to support dogs
instead of users, I would rather modify one SQL query.
Alternatively, you could also rename your user_name column
to just name. This would maximize reusability, but may hurt
your ability to understand more complex SQL queries and
database designs.
You might be thinking this class is overly complex. After
all, you can probably code all of this in 15 lines within a
regular PHP page. So where's the advantage? Well, look at
how we use our objects:
Really, that's 4 lines of code to echo out all of the
users in our table. All of the database connection,
querying, and real code is sitting behind the scenes.
Remember, we are going to include our classes as separate
files. On top of that, our classes are very reusable (aka
modular). Our code is beautifully generalized and
hidden from plain sight. It should also coded semantically,
so it's easy to understand. Debugging and maintenance time
should be decreased significantly. In the end, we're going
to reuse this code for many sites and save tons of time and
energy.
So that's a basic user table accessed with a
UsersGroup class. But what if we want some users to
be Administrators and others just plain Users - how can we
do that? For the answer, let's continue on with the topic of
inheritance.
To make this system more robust, we don't want all of the
users in our group to have the same status. Some users need
to be administrators, others moderators, and others just
regular users. How can we account for this in our objects?
The answer is nheritance - the ability for one
class to inherit methods and properties from another class.
First, let's take a look at inheritance in code:
As you can see, our Admin
object has inherited the functionality of the User
class using the keyword extends. On top of
that, our Admin is given some additional
functionality. In this case, our User class is
known as the superclass. In PHP, a class may only inherit
one superclass. There are more nuances to inheritance, but
this tutorial will only cover the basics. In a more
realistic scenario, we would code more functionality for
just administrators. Perhaps something like:
For the sake of time and focus, these methods haven't
actually been coded. But this should give you some insight
into how inheritance works and why it can be useful.
Continue on for a few parting words and direction.
By now, you should understand what objects, how to create
them, and how to access their properties and methods. This
tutorial is by no means all-encompassing. In fact, this is
just the tip of the iceberg and was designed as such. For
further reading, I suggest HP5: Objects, Patterns, and
Practice by Matt Zandstra. In addition, you could read
through the
OOP documentation provided at php.net.
As you begin to understand OOP more and your PHP code
becomes more object oriented, you will find more code
reusable and ultimately save time and energy. Pre-existing
code resources such as
PEAR and
PHPClasses.org will become increasingly useful.
If you have questions related to this tutorial or PHP in
general, post them in the
Server-Side forum here at kirupa.com.
 |
Esherido |
|