Abstracting Database Access Using Polymorphism with Objects in PHP 5

Polymorphism is an object-oriented programming concept that can be difficult to understand. This article, the first of a three-part series, walks you through the basics of Polymorphism so that you can make use of it in your own applications. The specific example in this article will show you how to use it with different database systems.

Introduction

Since the introduction of a highly improved object model in PHP 5, developing object-based applications with the latest version of this neat scripting language has been a greatly simplified process. This is naturally due to the implementation of diverse and powerful object-oriented features, such as visibility of class members, type hinting and exceptions, to name a few.

However, while it should be admitted that the aforementioned improvements indeed facilitate working with classes and objects in a straightforward way, it’s also true that building object-oriented applications can be a hard-to-master process. Most of the time this is because of inadequate knowledge of the main pillars of the object-oriented paradigm.

In this case, you’ll possibly know that I’m talking about Inheritance and Polymorphism. But what can be wrong with putting these theoretical concepts into practice, after all? Well, if you’ve been developing object-based programs for a while, then you’ve probably been consciously defining parent classes here and there. Logically you’ve also created numerous subclasses to perform concrete tasks.

I have to admit that Inheritance is rather easy to grasp. It can be applied successfully with only a decent background in object-oriented programming. Nonetheless, there’s a part of this schema that very often is completely omitted, or misused, in the best case. As you may have guessed, I’m speaking of Polymorphism, certainly a concept that presents some abstract aspects. Consequently, it’s much harder to apply than Inheritance, at least in a real-world context.

But take a deep breath and think twice. Actually, in the arena of object-based programming it isn’t too difficult to understand how objects that belong to the same family can have different behaviors, even when they’re using the same methods. And besides, there’s an additional question that needs to be answered: how can this feature be used to create more efficient PHP applications?

As you can see, questions come up very quickly when it comes to taking advantage of Polymorphism in PHP. This implies that the subject in question deserves a closer look. Therefore, keeping in mind the interest you might have in how to get the most out of polymorphic objects in PHP 5, in this three part series, I’m going to take a deeper look at some concrete situations where Polymorphism can assists in developing more robust and efficient object-based applications.

More specifically speaking, in this first installment of the series, I’ll be explaining how to implement Polymorphism to achieve a high level of abstraction when accessing different database systems. Subsequent articles will cover the use of polymorphic objects to build dynamic web documents and validate user-supplied input.

So, having established the topics that I plan to treat in this group of articles, let’s get started now!

{mospagebreak title=What shouldn’t be done when accessing distinct database systems}

As I explained in the introduction, Polymorphism can be used in all sorts of clever ways to build smarter applications. But in this particular case, I’m going to demonstrate how to use it to create a simple — yet robust — database abstraction layer that can be utilized to access different database systems.

However, I’m going to start on the opposite side. First I’ll show you a poor implementation of a sample database abstraction layer, which will take care of working with MySQL and SQLite simultaneously. The key point is that this application isn’t going to take advantage of Polymorphism.

Having said that, please take a look at the signature of the following class. As I explained before, it  will be capable of using the two database systems previously mentioned. Here is how the class in question looks:

// define ‘DBHandler’ class (poor implementation of a class and
lack of Polymorphism)
class DBHandler{
  
private $db;
  
private $result;
  
private $mysqli;
  
private $sqlite;
  
public function __construct($db,$host,$user,$password,$database){
    
if($db!=’MySQL’&&$db!=’SQLite’){
      
throw new Exception(‘Invalid type of database class’);
    
}
    
$this->db=$db;
    
if($this->db==’MySQL’){
      
$this->connectMySQL($host,$user,$password,$database);
    
}
    
else{
      
$this->connectSQLite($database);
    
}
  
}
  
// run query
   
public function query($query){
    
if($this->db==’MySQL’){
      
$this->queryMySQL($query);
    
}
    
else{
      
$this->querySQLite($query);
    
}
   }
   // fetch row
  
public function fetchRow(){
    
if($this->db==’MySQL’){
      
return $this->fetchRowMySQL();
    
}
    
else{
      
return $this->fetchRowSQLite();
    
}
  
}
  
// connect to MySQL
  
private function connectMySQL($host,$user,$password,$database){
    
$this->mysqli=new MySQLI($host,$user,$password,$database);
    
if(mysqli_connect_errno()){
      
throw new Exception(‘Error connecting to MySQL database
server : ‘.$this->mysqli->error);
    
}
  
}
  
// run query against MySQL database
  
private function queryMySQL($query){
    
if(!$this->result=$this->mysqli->query($query)){
      
throw new Exception(‘Error running query ‘.$query.’ :
‘.$this->mysqli->error);
    
}
  
}
  
// fetch row from MySQL database table
  
private function fetchRowMySQL(){
    
return $this->result->fetch_array(MYSQL_ASSOC);
  
}
  
// create SQLite database
  
private function connectSQLite($database){
    
$this->sqlite=new SQLiteDatabase($database);
    
// this statement should be executed only once
    
$this->sqlite->query("BEGIN;
CREATE TABLE users (id INTEGER(4) PRIMARY KEY, name CHAR(255),
email CHAR(255));
INSERT INTO users (id,name,email) VALUES
(NULL,’User1′,’user1@domain.com’);
INSERT INTO users (id,name,email) VALUES
(NULL,’User2′,’user2@domain.com’);
INSERT INTO users (id,name,email) VALUES
(NULL,’User3′,’user3@domain.com’);
COMMIT;");
  
}
   
// run query against SQLite database table
  
private function querySQLite($query){
    
if(!$this->result=$this->sqlite->query($query)){
      
throw new Exception(‘Error running query ‘.$query.’ :
‘.$this->mysqli->error);
    
}
  
}
  
// fetch row from SQLite database table
  
private function fetchRowSQLite(){
    
return $this->result->fetch(SQLITE_ASSOC);
  
}
} 

If you take some time to carefully examine the definition of the above class, you’ll see that it’s been provided with the ability to perform a few useful tasks, like connecting either to MySQL or SQLite, in addition to running queries, fetching and counting database table rows in both database applications, and so on. Quite simple, right?

In addition, a couple of examples on how to use this class are listed below:

try{
  
// use ‘DBHandler’ class (poorly implemented example)
  
$dbh=new DBHandler(‘MySQL’,’host’,’user’,’password’,’database’);
  
$dbh->query(‘SELECT name,email FROM users’);
  
while($row=$dbh->fetchRow()){
    
echo $row['name'].’ ‘.$row['email'].'<br />';
  
}
}
catch(Exception $e){
   echo $e->getMessage();
   exit();
}

try{
  
// use ‘DBHandler’ class (poorly implemented example)
  
$dbh=new DBHandler(‘SQLite’,’host’,’user’,’password’,’database’);
  
$dbh->query(‘SELECT name,email FROM users’);
  
while($row=$dbh->fetchRow()){
    
echo $row['name'].’ ‘.$row['email'].'<br />';
  
}
}
catch(Exception $e){
  
echo $e->getMessage();
  
exit();
}

At first glance, the previous abstraction class seems to fit the requirements for working with both database systems. However, it should be noticed that the code used to perform this process is extremely inefficient.

Why do I say this, if the prior class does what’s expected? Well, if you study the respective definitions of many of its methods, you’ll see that there’s always a conditional statement that checks to see whether the used database system is MySQL or SQLite. This is really a poor approach from a development point of view, and certainly can be even worse if more methods are added to the original class. Imagine how much time will be wasted when updating this abstraction class!

The previous class isn’t taking advantage of Polymorphism. This feature could facilitate the maintainability of a complete database application. It could also noticeably improve the way that the different database systems are accessed.

But, how can we take advantage of this feature in a truly useful fashion? To see how a simple database abstraction layer can be built using the functionality provided by a few polymorphic classes, you’ll have to read the following section.

{mospagebreak title=Using Polymorphism to create a database abstraction layer}

In the previous section you saw how a simple database abstraction layer can be created to access both MySQL and SQLite systems. However, the major drawback with this class was the poor implementation presented for many of its methods, since none of them used Polymorphism to improve the way that database systems are accessed.

Considering this issue, I’m going to define a new set of classes, which this time will take advantage of Polymorphism to work with the two database systems.

Having said that, here is the signature of the first class that I plan to create in this section. This one is simply an abstract interface, from which I’ll derive a couple of subclasses for working specifically with MySQL and SQLite.

This abstract class looks like this:

// define abstract ‘DBConnector’ class
abstract class DBConnector{
  
abstract public function __construct($host,$user,$password,$database);
  
abstract public function query($query);
  
abstract public function fetchRow();
  
abstract public function countRows();
}

As you can see, the above abstract class is indeed very easy to follow, since it’s merely an interface that defines generically the methods that will be implemented later by the respective subclasses.

As I stated before, these subclasses will be responsible for working specifically either with MySQL or SQLite. Let me show you the corresponding signatures for each of them. Here they are:

// define concrete ‘MySQL’ class
class MySQL extends DBConnector{
  
private $mysqli;
  
private $result;
  
// connect to MySQL
  
public function __construct($host,$user,$password,$database){
    
$this->mysqli=new MySQLI($host,$user,$password,$database);
    
if(mysqli_connect_errno()){
      
throw new Exception(‘Error connecting to MySQL database
server : ‘.$this->mysqli->error);
    
}
  
}
  
// run query against database
  
public function query($query){
    
if(!$this->result=$this->mysqli->query($query)){
      
throw new Exception(‘Error running query ‘.$query.’ :
‘.$this->mysqli->error);
    
}
  
}
  
// fetch database table row
  
public function fetchRow(){
    
return $this->result->fetch_array(MYSQL_ASSOC);
  
}
  
// count database table rows
   
public function countRows(){
    
if(!$rows=$this->result->num_rows){
      
return ‘No database rows were returned by the query';
    
}
    
return $rows;
  
}
}

// define concrete ‘SQLite’ class
class SQLite extends DBConnector{
  
private $sqlite;
  
private $result;
  
public function __construct($host,$user,$password,$database){
    
$this->sqlite=new SQLiteDatabase($database);
    
// this statement should be executed only once
    
$this->sqlite->query("BEGIN;
CREATE TABLE users (id INTEGER(4) PRIMARY KEY, name CHAR(255),
email CHAR(255));
INSERT INTO users (id,name,email) VALUES
(NULL,’User1′,’user1@domain.com’);
INSERT INTO users (id,name,email) VALUES
(NULL,’User2′,’user2@domain.com’);
INSERT INTO users (id,name,email) VALUES
(NULL,’User3′,’user3@domain.com’);
COMMIT;");
  
}
  
// run query against database
  
public function query($query){
    
if(!$this->result=$this->sqlite->query($query)){
      
throw new Exception(‘Error running query ‘.$query.’ :
‘.$this->sqlite->error);
    
}
  
}
  
// fetch database table row
  
public function fetchRow(){
    
return $this->result->fetch(SQLITE_ASSOC);
  
}
  
// count database table rows
  
public function countRows(){
    
if(!$rows=$this->result->numRows()){
      
return ‘No database rows were returned by the query';
    
}
    
return $rows;
  
}
}

Definitely, things are getting really exciting now! As you can see, the two subclasses listed above present the same methods (remember that they were derived from the parent "DBConnector"), but in this case each of them is implemented differently so they can work with either MySQL or SQLite.

Of course, defining these child classes in this way implies having two completely independent structures, which can be easily updated with minor hassles. Nonetheless, the most important thing to note here is that I created two polymorphic classes, since they belong to the same family of objects, but behave differently using the same methods. Quite good, right?

Having these handy polymorphic classes at our disposal, it’s possible to create highly expansible database abstraction layers. If a new database system needs to be added to the layer in question, the process is reduced only to deriving the concrete subclass that deals with that specific system. Period.

However, you may be wondering…how does a given application know which class to use according to the type of database system being utilized? The answer is that it simply uses a factory class that returns to client code the correct type of object to work with MySQL, SQLite or whatever system you may want to incorporate into your application.

To demonstrate the previous concept, below I included the signature of a simple factory class. As I said before, it is tasked with spawning the correct type of database object, according to the database requirements of a specific application.

Given that, here’s how this brand new class looks:

// define ‘DBFactory’ class
class DBFactory{
  
// create database class instance
  
public function createDB
($db,$host=”,$user=”,$password=”,$database=’db.sqlite’){
    
if($db!=’MySQL’&&$db!=’SQLite’){
      
throw new Exception(‘Invalid type of database class’);
    
}
    
return new $db($host,$user,$password,$database);
  
}
}

Wasn’t that simple? I bet it was! As you can see, the above factory class implements the required logic to create two specified database objects for working with MySQL and SQLite. Logically, after instantiating the correct type of object, the procedure for handling a given database system is only a matter of using its respective methods.

Now, do you realize the convenience of working with polymorphic objects? I hope you do.

Okay, having defined the group of classes required to implement this simple database abstraction layer, it’s time to leap forward and develop a functional example, where all these classes will be put to work in conjunction. Doing so, you’ll have a better idea of how Polymorphism can play a relevant role when using multiple database systems.

To see how the previously defined classes will be used together in the same practical example, keep reading.

{mospagebreak title=Demonstrating the functionality of Polymorphism}

In this section I’m going to create a couple of hands-on examples, which hopefully will help you understand more easily the convenience of working with polymorphic objects.

This being said, here is the first code sample. It demonstrates how easy it is to interact with MySQL using the database abstraction layer that I developed earlier. The corresponding code listing is as follows:

(example using MySQL database server)
try{
  
// use Factory pattern and Polymorphism to work with MySQL
  
$factoryInstance=new DBFactory();
  
$db=$factoryInstance->createDB
(‘MySQL’,’host’,’user’,’password’,’database’);
  
$db->query(‘SELECT name,email FROM users’);
  
while($row=$db->fetchRow()){
    
echo $row['name'].’ ‘.$row['email'].'<br />';
  
}
  
echo ‘Number of rows returned by the query :’.$db->countRows
();
  
/* displays the following
  
user1 user1@domain.com
  
user2 user2@domain.com
  
user3 user3@domain.com
  
user4 user4@domain.com
  
user5 user5@domain.com
   user6 user6@domain.com
  
user7 user7@domain.com
  
user8 user8@domain.com
  
user9 user9@domain.com
  
user10 user10@domain.com
   Number of rows returned by the query :10

   */
}
catch(Exception $e){
  
echo $e->getMessage();
  
exit();
}

As shown above, accessing the MySQL database server is extremely simple by using Polymorphism. The previous example uses the "query()", fetchRow()" and "countRows()" methods to perform some common tasks associated with MySQL, such as running queries and fetching/counting rows. But this advantage is even more clear if you look at the following example. It uses the same methods, but this time accesses the SQLite database system.

Assuming that a sample SQLite database has been populated with basic data, the respective code listing is as follows:

(example using SQLite database system)

try{
  
// use Factory pattern and Polymorphism to work with SQLite
  
$factoryInstance=new DBFactory();
  
$db=$factoryInstance->createDB(‘SQLite’);
  
$db->query(‘SELECT name,email FROM users’);
  
while($row=$db->fetchRow()){
    
echo $row['name'].’ ‘.$row['email'].'<br />';
  
}
  
echo ‘Number of rows returned by the query :’.$db->countRows
();

   /* displays the following:

   User1 user1@domain.com
  
User2 user2@domain.com
  
User3 user3@domain.com
   Number of rows returned by the query :3

   */

}
catch(Exception $e){
  
echo $e->getMessage();
  
exit();
}

Definitely, after examining the previous example, you’ll have to agree with me that building a database abstraction layer using polymorphic objects is by far a much better approach than the one shown in the beginning of this tutorial.

Naturally, I’m not saying here that you have to reinvent the wheel and write your own abstraction layers; there are many excellent packages available on the web. But I do want you to understand the advantages of using Polymorphism when building your PHP applications, since the concept can be rapidly extended to other areas.

Final thoughts

That’s all for the moment. In this first article of the series, I demonstrated in a friendly way how to use polymorphic classes to build a simple database abstraction layer. Nevertheless, this is only the beginning, since in the next part I’m going to teach you how to use polymorphism to create dynamic web pages. You won’t want to miss it!

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan