Building Object-Oriented Database Interfaces in PHP: Updating the Application to PHP 5

In this fourth and final article in the tutorial series, Alejandro Gervasio updates the “DBIGenerator” class developed in the previous articles. The new version incorporates features in PHP 5, such as member visibility, exceptions, and other useful items.

Introduction

This is the final article in the series “Building Object-Oriented Database Interfaces in PHP.” Welcome back. After going through the previous articles, we’ve introduced ourselves to the interesting subject of database interfaces, explaining some key concepts as a straightforward way to get a better grounding in the topic. I provided a friendly set of examples, aimed primarily at implementing these programming structures in real applications.

Despite the fact that the subject is far from being fully covered, due mainly to the different approximations applied to accessing database tables through centralized mechanisms, hopefully the issue has been thoroughly treated.

However, as you know, PHP is a fast-growing language, which has taken a large step forward with the release of PHP 5. As this version is widely adopted by developers and hosting service providers, we need to tackle this rather uncovered aspect, porting most of the source code shown in the previous articles to PHP 5, in order to get updated to the current PHP development tendencies.

Confronted with this situation, in this last article I’ll show the updated version of the “DBIGenerator” class, along with a few basic examples of usage, incorporating some of the most exciting new features present in PHP 5, such as member visibility, exceptions and other goodies.

Whether you’re a developer currently using PHP 4 or making the leap to PHP 5, the article provides you with a friendly introduction to implementing database interfaces in PHP 5.

With the preliminaries out of the way, let’s get started.

{mospagebreak title=Porting Database Interfaces to PHP 5: member visibility, exceptions and more}

Porting code developed in PHP 4 to PHP 5 is not really a difficult task. Since the new Zend 2 PHP engine maintains a good level of backward compatibility, the updating process shouldn’t present major problems. However, when an object-oriented approach is implemented, things are a little bit different.

As you probably know, PHP 5 presents a highly improved Object Model, allowing you to declare the visibility of class members and methods as private, public or protected, nearly similar to the Java model, among other useful things. Besides, it incorporates Exceptions as a proven method for implementing error handling in object-oriented environments, which resembles the models present in other popular programming languages.

But here, I’m not going to take the long road by explaining these features in detail. If you want to learn more about them, the official PHP site is just one click away. Instead, I’ll offer a brief explanation, which you will find useful for better understanding the ported code of the “DBIGenerator” class.

Well, having provided extensive examples of the use of this class in previous articles, let’s take a look at its updated code, and then, in turn, spot the differences as compared to the prior version. Here’s the ported class’ code:

class DBIGenerator{
    private $table;
    private $name;
    private $path;
    public function __construct($table,$name=’default_file.php’,
            $path=’DEFAULTPATH/’){
        $this->table=$table;
        $this->name=$name;
        $this->path=$path;
    }
    public function generate(){
        // build class header
        $str='<?php class ‘.$this->name.'{‘;
        if(!$result=mysql_query(‘SHOW COLUMNS FROM ‘.$this->table)){
            throw new Exception(‘Failed to run query’);
        }
        // build data member declaration
        if(mysql_num_rows($result)<1){
            throw new Exception(‘Not available columns in table’);
        }
        $methods=”;
        while($row=mysql_fetch_array($result,MYSQL_ASSOC)){
            $str.=’private $’.$row[‘Field’].’=”;’;
            $methods.=’public function set’.$row[‘Field’].'($’.$row
                 [‘Field’].’){$this->’.$row[‘Field’].’=$’.$row
                 [‘Field’].’;}’;
            $methods.=’public function get’.$row[‘Field’].'(){return 
                 $this->’.$row[‘Field’].’;}’;
            // store field names in array
            $fields[]=$row[‘Field’];
        }
         // build empty constructor
        $str.=’public function __construct(){}’;
         // build modifiers and accessors
        $str.=$methods;
         // build load() method
        $str.=’public function load(){$r=mysql_query(“SELECT * FROM
                 ‘.$this->table.’ WHERE id=’$this->id'”);’;
        $str.=’return mysql_fetch_array($r,MYSQL_ASSOC);}’;
        // build submit() method
        $str.=’public function submit(){mysql_query(“INSERT INTO ‘.$this-
                 >table.’ SET ‘;
        foreach($fields as $field){
            $str.=($field!=’id’)?$field.’=’$this->’.$field.”,’:”;
        }
        $str.='”);$this->id=mysql_insert_id();’;
        $str=preg_replace(“/,”/”,”””,$str).’}’;
        // build update() method
        $str.=’public function update(){mysql_query(“UPDATE ‘.$this-
                 >table.’ SET ‘;
        foreach($fields as $field){
            $str.=($field!=’id’)?$field.’=’$this->’.$field.”,’:”;
        }
        $str=preg_replace(“/,$/”,””,$str);
        $str.=’ WHERE id=’$this->id'”);}’;
        // build delete() method
        $str.=’public function delete(){mysql_query(“DELETE FROM ‘.
                 $this->table.’ WHERE id=’$this->id'”);}’;
        $str.=’}?>’;
        // open or create class file
        if(!$fp=fopen($this->path.$this->name.’.php’,’w’)){
            throw new Exception(‘Failed to create class file’);
        }
        // lock class file
        if(!flock($fp,LOCK_EX)){
            throw new Exception(‘Unable to lock class file’);
        }
        // write class code to file
        if(!fwrite($fp,$str)){
            throw new Exception(‘Error writing to class file’);
        }
        flock($fp,LOCK_UN);
        fclose($fp);
        // delete temporary variables
        unset($fp,$str,$row,$fields,$field,$methods);
    }
    public function getObject(){
        // check if class file exists
        if(!file_exists($this->path.$this->name.’.php’)){
            throw new Exception(‘Failed to include class file’);
        }
        require_once($this->path.$this->name.’.php’);
        // create data access object
        return new $this->name;
    }
}

At first glance, the above listed code presents some minor modifications. Of course, its functionality is the same, but there are several differences that need to be explained, at least for those developers making their first incursions in PHP 5.

The first thing to note is that each class member has been declared as private. This means that they cannot be accessed from outside the class. Any attempt to do so will result in a fatal error. Also, in a similar way, the “generate()” and “getObject()” methods are declared as public, so they can be accessed from outside.

While all of the methods that don’t have a explicit visibility declaration are considered by default as public by the PHP interpreter, specifying its visibility helps to have a clearer idea about how they can be accessed in the context of an application.

Certainly, there are other differences that we’ll explain briefly. As you can see, the constructor has been replaced with the “__construct()” function, which essentially performs the same task. Whenever an object is instantiated, this method will be executed automatically. However, PHP 5 still supports the traditional way of defining a class constructor, that is declaring a method that has the same name as that of the class.

In addition, the class uses Exceptions to handle basically any error condition, by throwing a new exception each time a potential error might occur. This mechanism has a significant advantage over the common “die()” or “trigger_error()” PHP functions, since it provides an efficient way to handle different runtime errors through a centralized mechanism, by delegating this responsibility to a specific method within the application. As a general rule, errors shouldn’t be handled by the code that generated them. Once an exception has been thrown within the class, it may be caught by a “catch” statement, as we’ll see shortly.

The last thing to highlight regarding the class is that the same features are applied to the dynamically generated database interface class. Notice that every respective method, “load()”, “submit()”, “update()” and “delete()”, is created specifying their visibility, declared as public. Similarly, the constructor is defined as “__construct()” as well.

At this point, we’ve reviewed the most relevant changes made to the class, in order to work with the nice object features of PHP 5. Still interested in knowing more? All right. Keep reading to find out how the class can be set up to work in a PHP 5 controlled environment.

{mospagebreak title=Using the class in a object-oriented scenario: the “try” and “catch” blocks}

As I said before, updating the code to work in PHP 5 is really simple. I’ll build several examples that demonstrate the use of the “DBIGenerator” class, performing single-row DML operations on a sample “users” database table. Although I’ve thoroughly implemented these operations in my previous articles, in this case I’ll take advantage of some handy PHP 5 capabilities, for inserting, updating and deleting table rows.

The first example simply adds a new row to the sample “users” table, as listed below:

// include class files
function __autoload($class_name) {
    require_once ‘classes/’.$class_name.’class.php5′;
}
try {
    // connect to MySQL
    $db=new MySQL(array(‘host’=>’host’,’user’=>’user’,’password’=>
          
‘password’,’database’=>’databasename’));
    // instantiate a new DBIGenerator object
    $gn=new DBIgenerator(‘users’,’user’,’classes/’);
    // generate class file
    $gn->generate();
    // get $user object
    $user=$gn->getObject();
    // set object properties
    $user->setfirstname(‘John’);
    $user->setlastname(‘Coffey’);
    // insert row into table
    $user->submit();
    echo ‘Row successfully inserted’;
}
catch (Exception $e){
    echo $e->getMessage();
    exit();
}

If you’ve read the previous parts of this series (I hope you did), the above example is very understandable. We use the “DBIGenerator” class to create on the fly a “user” database interface within the “classes/” directory. This class is used to directly “interface” with the “users” table, by providing a single access point to it.

After calling the “generate()” method, the “user” DB interface class is built transparently on the background, and defined as follows:

class user{
    private $id=”;
    private $firstname=”;
    private $lastname=”;
    public function __construct(){}
    public function setid($id){
        $this->id=$id;
    }
    public function getid(){
        return $this->id;
    }
    public function setfirstname($firstname){
        $this->firstname=$firstname;
    }
    public function getfirstname(){
        return $this->firstname;
    }
    public function setlastname($lastname){
        $this->lastname=$lastname;
    }
    public function getlastname(){
        return $this->lastname;
    }
    public function load(){
        $r=mysql_query(“SELECT * FROM users WHERE id=’$this->id'”);
        return mysql_fetch_array($r,MYSQL_ASSOC);
    }
    public function submit(){
        mysql_query(“INSERT INTO users SET firstname=’$this->
            firstname’,lastname=’$this->lastname'”);
        $this->id=mysql_insert_id();
    }
    public function update(){
        mysql_query(“UPDATE users SET firstname=’$this->
            firstname’,lastname=’$this->lastname’ WHERE id=’$this->id'”);
    }
    public function delete(){
        mysql_query(“DELETE FROM users WHERE id=’$this->id'”);
    }
}

As you can see, the class is generated by specifying the visibility for the data members, which are declared as private, and the respective methods, that are set to be public. The rest of the code remains nearly identical to the PHP 4 version.

However, let’s focus our attention on the snippet that adds a row to the “users” table. The first thing to note is that we’re including the required class files using the “__autoload()” function:

// include class files
function __autoload($class_name) {
    require_once ‘classes/’.$class_name.’class.php5′;
}
 

This function is very useful for automatically loading the necessary class files, whenever we try to instantiate an object from a given class, without the need to code multiple “require_once()” statements. Of course, the class file could have been included in the traditional way, but in this example I decided to use this handy function.

The last relevant issue within the code is the usage of the “try-catch” blocks, for handling potential runtime errors. If you have a background in Java, these blocks should already be familiar. However, if they’re unknown to you, take it easy, because I’ll give a short explanation of their meaning.

Take into account that the “DBIGenerator” class throws a new Exception object when an error condition occurs, such as performing the query to obtain the field names of the table, or writing the class code to a file. Similarly, the MySQL abstraction class throws the proper exceptions when connecting and selecting the specified database. Doing so, we’ve wrapped the code into a “try” block, and defined another “catch” block to handle all of the exceptions.

In this particular case, I’ve chosen to pass to the constructor of the Exception class a simple error message that will be displayed before exiting the script. Since this class provides the “getMessage()” method, we’re able to use it to show the messages, like this:

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

Certainly, we could have gone further in handling an error condition (i.e. writing the error to a log file). However, in order to give a quick introduction to Exceptions in PHP, it’s more than enough.

To end this overview, once the $user object is made available within the script, we add a new row to the table by simply setting the values for the “firstname” and “lastname” fields, and lastly inserting the data through the “submit()” method:

 $user=$gn->getObject();
 // set object properties
 $user->setfirstname(‘John’);
 $user->setlastname(‘Coffey’);
 // insert row into table
 $user->submit();
echo ‘Row successfully inserted’;

Okay, I think that was really easy, huh? In the next few lines we’ll describe the process for updating and deleting a table row. Keep reading.

{mospagebreak title=Completing the round: updating and deleting rows}

I suppose that the first example has been more than illustrative for introducing several features specifically inherent to PHP 5. From this point, the rest of the operations for either updating or deleting a row from the database table shouldn’t be a troubling process. Therefore, here’s the sample code for updating a row:

// include class files
function __autoload($class_name) {
    require_once ‘classes/’.$class_name.’class.php5′;
}
try {
    // connect to MySQL
    $db=new MySQL(array(‘host’=>’host’,’user’=>’user’,
         ‘password’=>’password’,’database’=>’databasename’));
    // instantiate a new DBIGenerator object
    $gn=new DBIgenerator(‘users’,’user’,’classes/’);
    // generate class file
    $gn->generate();
    // get $user object
    $user=$gn->getObject();
    // set object properties
    $user->setid($_GET[‘id’]);
    $user->setfirstname(‘Paul’);
    $user->setlastname(‘Hedgecomb’);
    // update table row
    $user->update();
    echo ‘Row successfully updated’;
}
catch (Exception $e){
    echo $e->getMessage();
    exit();
}
 

The above example implements the same concepts described in the first case. We directly connect to MySQL, select the database, and instantiate a “DBIGenerator” object. Then, the “user” DB interface class is generated, returning a $user object. Next, a given row is updated with the new values for the “firstname” and “lastname” fields.

A short explanation is in order here. Notice that we’re obtaining the ID of the row to be updated from a hypothetical “id” variable passed on the URL querystring, as we see below:

$user->setid($_GET[‘id’]);

This parameter usually might be dynamically generated from a regular link, similar to this basic example:

<a href=”update.php?id=10″ title=”update row”>Update row</a>

I guess you get the idea. Finally, the row is updated by calling the “update()” method:

$user->update();

As you might guess, deleting a row is nearly identical to the updating process. It’s as simple as this:

// include class files
function __autoload($class_name) {
    require_once ‘classes/’.$class_name.’class.php5′;
}
try {
    // connect to MySQL
    $db=new MySQL(array(‘host’=>’host’,’user’=>’user’,
          ‘password’=>’password’,’database’=>’databasename’));
    // instantiate new DBIGenerator object
    $gn=new DBIgenerator(‘users’,’user’,’classes/’);
    // generate class file
    $gn->generate();
    // get $user object
    $user=$gn->getObject();
    // delete row from table
    $user->setid($_GET[‘id’]);
    $user->delete();
    echo ‘Row successfully deleted’;
}
catch (Exception $e){
    echo $e->getMessage();
    exit();
}
 

Wasn’t that simple? In this case, we’ve replaced the “update()” method with the “delete()” method, thus removing the specified row from the database table.

Okay, I think that’s all for now. Having described in detail how DML operations are performed using the PHP 5 updated version of the “DBIGenerator” class, our round trip around database interfaces has already finished. As you know, every journey has to end, so be patient for a little longer and join me in reading the conclusions.

Conclusion

Over this series, we’ve learned the core concepts behind object-oriented database interfaces, as an efficient and secure programming mechanism to access databases utilizing a single communication point.

Moreover, we’ve ranged from a simplistic approximation, by accomplishing single-row DML operations, to a more complex application, working with many database interfaces and multiple tables. Certainly the experience has proven to be instructive and truly fun.

Database interfaces are powerful tools for implementing in large projects, where maintenance of SQL code might be a sometimes cumbersome task. Thus, if your next web project looks like a 10,000 line application, consider implementing them to solve most of the hard-coded SQL issues.

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye