Simplify Business Logic with PHP DataObjects
by Darryl Patterson
08/05/2004
Simple Data Objects with PHP 5
Working with a database is an everyday exercise for web developers these
days. From simple form processing to large-scale web applications, we almost
always need a database. After working on a few projects, it doesn't take very
long to realize that the same four simple database tasks repeat many times in
virtually all projects. These four tasks are:
- Finding records (
SELECT).
- Updating existing records (
UPDATE).
- Adding new records (
INSERT).
- Removing records (
DELETE).
You find yourself re-typing or copying and pasting your queries throughout
your code, slightly modifying them as necessary in various places. Many folks
resort to a data abstraction layer, such as Pear::DB or DBX. Using a data
abstraction layer is a good thing, but its main goal is to make the RDBMS
transparent, allowing you to change database vendors fairly easily. A database
abstraction layer doesn't offer a way to abstract the table structure
of your database, since it can't standardize the way your functional code
accesses data in your database. This is where having a separate data access
layer can help out. You can implement data access layers in more than one way,
but here, we're interested in DataObjects.
The concept of DataObjects comes from some very well-documented design
patterns, namely the Data
Access Object and Transfer
Object patterns. These patterns can be quite complex, but with a little imagination,
we can use their fundamental ideas and purpose to make our own data layer in
PHP 5 much easier to work with. Let's dig in.
What is a DataObject?
As just mentioned, the idea of a DataObject comes from a design pattern. If
you've ever looked into design patterns at all, you'll know that they often
depend on object orientation. That said, we will make extensive use of PHP 5's
new object model. We'll also use MySQL for the examples (although it's also
easy to use something like Pear::DB).
Essentially, a DataObject is a coded class that directly represents a table
in your database -- you will code a class for every table. The class will
have member variables that exactly match the fields in your table, as well as a
set of methods or functions that perform at least the four basic tasks
mentioned above. Suppose we have a simple table for holding user info:
TABLE: User
userId INT
firstName VARCHAR(30)
lastName VARCHAR(40)
email VARCHAR(100)
Now that we have a table, we'll code a corresponding class whose member
variables have the same field names found in the table. I tend to prepend my
DataObject class names with DO_ to avoid confusing them with other
classes of similar names; this is a common pattern in PHP to simulate
namespaces. Here's the code:
class DO_User {
public $userId;
public $firstName;
public $lastName;
public $email;
}
This simple little wrapper represents a single row from our table. An
instance of DO_User can hold only one row of data at a time. How
do we fetch data from the database into this object? Let's add a new method called get() to
our class to query the database for one specific
user. We'll provide the userId (the primary key) of the user we
want to fetch as a parameter.
File contents of: class-DO_User.php
<?php
class DO_User {
public $userId;
public $firstName;
public $lastName;
public $email;
// This function will perform a select on the table looking for
// a specific userId.
public function get($userId)
{
$sql = 'SELECT * FROM User WHERE userId='
. mysql_escape_string($userId);
$rs = mysql_query($sql);
$row = mysql_fetch_array($rs);
$this->userId = $row['userId'];
$this->firstName = $row['firstName'];
$this->lastName = $row['lastName'];
$this->email = $row['email']
}
}
?>
With this very simple data object, we can now interact with our database
using only PHP code. We need no SQL to use our database. Here is a script that
uses this DataObject to fetch and display the user's data to a web browser:
<?php
include_once('class-DO_User.php');
$user = new DO_User();
// We'll use a literal integer here,
// but this could come from anywhere,
// such as $_POST or $_GET
$user->get(5);
?>
<html>
<head>
<title>User Info</title>
</head>
<body>
<p>Here is the user info:</p>
<table border="1">
<tr>
<td>User ID</td>
<td><?=$user->userId?></td>
</tr>
<tr>
<td>First Name</td>
<td><?=$user->firstName?></td>
</tr>
<tr>
<td>Last Name</td>
<td><?=$user->lastName?></td>
</tr>
<tr>
<td>Email</td>
<td><?=$user->email?></td>
</tr>
</table>
</body>
</html>
As you can see, using the DataObject is quite simple and very clean. The
get() method we added performs a simple query on the user table,
searching for the specific primary key (userId) for which we're looking.
Remember, whenever you query a table looking for equality on a primary key,
you'll only receive one record back. This works well for our simple DataObject,
but we'll discuss retrieving multiple rows a little later.
Notice that when the DataObject has found the record, it copies the record
data into the DataObject's member variables. This is why the names of the
member variables in the DataObject must match the column names in the table
exactly.