Object Interaction in PHP: Introduction to Composition, conclusion

In the first article of this series, the concept of composition in object-oriented programming was explained, and illustrated with an example that implemented composition using two simple classes. In this article, we will create a MySQL database wrapping class that uses the concept of composition.

Introduction

Welcome to the second part of the series “Object Interaction in PHP: Introduction to Composition.” Please don’t feel intimidated by that lengthy title. If you’ve been working with classes for a while, then you probably have a strong knowledge of what composition is about. However, for those developers just beginning to work with object-oriented programming in PHP, let’s explain briefly some definitions, in order to refresh some relevant concepts about the subject.

Speaking in general terms, composition occurs when one object possesses completely another object. We might say that the first object is directly responsible for the creation of the second one. Definitely, this technique within the OOP paradigm, has proven to be highly successful on medium or large websites, where a object-oriented approach is often needed.

In my previous article, I presented an illustrative example that implemented composition by using two simple classes, a “Page” class and a “Table” class, where this last one was directly created by the first one. The main purpose of the “Page” class was generating a regular HTML page, building the body section of the page using the functionality offered by the “Table” class, and rendering a row color-alternated table. Let’s take a quick look at these classes, so we can recapitulate what we’ve learned until now. The classes were defined like this:

class Page {

            var $title;

            var $html;

            function Page($title=’Default Page’){

                        $this->title=$title;

                        $this->html=”;

            }

            function makeHeader($header){

                        $this->html.='<html><head><title>’.$this->title.'</title></head><body>’.$header;

            }

            function makeBody($content=array()){

                        return new Table($this,$content);

            }

            function makeFooter($footer){

                        $this->html.=$footer.'</body></html>';

            }

            function display(){

                        return $this->html;

            }

}

Next, the second class looked like this:

class Table {

            var $page;

            var $content;

            var $id;

            function Table(&$page,$content){

                        $this->page=&$page;

                        $this->content=$content;

                        $this->id=’defaultID';

            }

            function setId($id){

                        $this->id=$id;

            }

            function build($colorA,$colorB){

                        $this->page->html.='<table id=”‘.$this->id.'” width=”100%”>';

                        $i=0;

                        foreach($this->content as $row){

                                    $bgcolor=($i%2)?$colorA:$colorB;

                                   $this->page->html.='<tr bgcolor=”‘.$bgcolor.'”><td>’.$row.'</td></tr>';

                                   $i++;

                        }

                        $this->page->html.='</table>';

                        return $this->page->html;

            }

}

As you can appreciate from the above code, our “Page” class fully owns the second “Table” object, since it creates an instance of it within its “makeBody()” method, in order to build the HTML table. Going back to the concept of composition, we might say that “Table” composes the “Page” object. At this time, I think that the issue was correctly understood. One possible implementation for these classes would be the following:

// include the classes

require_once ‘pageclass.php';

require_once ‘tableclass.php';

// instantiate a new Page object

$page=&new Page();

// make header

$page->makeHeader(‘<div>Header</div>’);

// set Table object parameters

$table=$page->makeBody(range(0,20));

$table->setId(‘maincontent’);

// build body table

$table->build(‘#ffcc00′,’#eeeeee’);

// make footer

$page->makeFooter(‘<div>Footer</div>’);

// display page

echo $page->display();

Simple and instructive, right? The above example creates our HTML page, including into its main section some content rendered in a table that displays rows using alternating colors. Fine, should we feel that composition has been completely mastered now? I don’t think so.

We need to put this technique to work, building an application that is used very frequently. In order to see how composition can be implemented in the real world, we’ll create a MySQL database wrapping class that uses the concept previously explained. What do you think? Doe this sound interesting? Good, let’s put our abilities to the test and start writing the class.

{mospagebreak title=Composition in a practical sense: building a MySQL wrapping class}

A MySQL wrapping class is one of the most common applications that we use very often, and certainly there are lots of good places on the Web where we can look for database classes. One of my favorites is PEAR::DB, which provides a lot of room to work with different database systems, and offers a wealth of advanced features, powerful enough to keep you entertained for a long time. If you feel curious about it, please visit http://pear.php.net/package/DB and give it a try.

However, for the purposes of this article, we’ll work with our own MySQL abstraction class, so we can see how composition is properly carried out. Building such a class is a pretty straightforward process, which has been covered in some of my previous articles explaining aggregation in PHP. Thus, I guess the creation process shouldn’t pose any difficulties.

Now, armed with a decent background about PHP database classes, we might define our own version in the following way:

class MySQLConnector {

            var $conId; // connection identifier

            var $host; // MySQL host

            var $user; // MySQL username

            var $password; // MySQL password

            var $database; // MySQL database

            // constructor

            function MySQLConnector($options=array()){

                        // validate incoming parameters

                        if(count($options)>0){

                                   foreach($options as $parameter=>$value){

                                               (!empty($value))?$this->{$parameter}=$value:die(‘Invalid parameter ‘.$parameter);

                                   }

                                   // connect to MySQL

                                   $this->connectDB();

                        }

                        else {

                                   die(‘No connection parameters were provided’);

                        }

            }

            // connect to MySQL server and select database

            function connectDB(){

                        if(!$this->conId=mysql_connect($this->host,$this->user,$this->password)){

                                    $this->isError(‘Error connecting to the server’);

                        }

                        if(!mysql_select_db($this->database,$this->conId)){

                                    $this->isError(‘Error selecting database’);

                        }

            }

            // perform query

            function performQuery($query){

                        if(!$this->result=mysql_query($query,$this->conId)){

                                   $this->isError(‘Error performing query ‘.$query);

                        }

                        // return new Result object

                        return new Result($this,$this->result);

            }

            // display errors

            function isError($errorMsg){

                        die($errorMsg.’ ‘.mysql_error());

            }

}

As you can see, the “MySQLConnector” class is closely similar to that presented in previous articles. As usual, the constructor accepts the parameters required to connect to MySQL, that is, host, username, password and the selected database, in the form of an $options array. Then, each parameter is properly validated and finally the connection to the database server is performed by calling the private method “connectDB()”.

Besides the constructor, the class presents an “isError()” method to handle basically any error that occurred during the course of the MySQL operations, stopping the class with a die statement, and displaying a custom error message along with the error generated by the mysql_error() function.

However, there is a noticeable difference in the “performQuery()” method. Notice that it takes a SQL query, then performs it against the database table, but this time it returns a new instance of a “Result” object. Here’s the list of the relevant method:

function performQuery($query){

            if(!$this->result=mysql_query($query,$this->conId)){

                        $this->isError(‘Error performing query ‘.$query);

            }

            // return new Result object

            return new Result($this,$this->result);

}

Since this method is creating a new “Result” object, we have a clue about what’s happening here. We’ve established a relationship between objects, where the object “Result” composes the “MySQLConnector” object. Indeed, the process of composition becomes very understandable.

Also, maintaining our database wrapping class as a completely separate piece of code from the “Result” class, implies a immediate benefit, because we’re clearly delimiting the operations related to each class. It’s important to know that we’re not conceiving a class as a bunch of properties and methods that don’t keep a well-defined relationship to each other.

So far, so good. We have our “MySQLConnector” class, which nicely creates the “Result” object. But, what’s next? It’s time to look at the structure of the “Result” class, so we can see how it works. Just join me in the next explanation.

{mospagebreak title=The other side of composition: the “Result” class}

We’ve already seen that the method “performQuery()” returns a new instance of a “Result” object. Therefore, there must be a class that defines the blueprints for it. Fortunately, this class is quite simple to read, and its definition is as follows:

class Result {

            var $mysql; // instance of MySQLConnector object

            var $result; // result set

            function Result(&$mysql,$result){

                        $this->mysql=&$mysql;

                        $this->result=$result;

            }

            // fetch row

            function fetchRow(){

                        return mysql_fetch_array($this->result,MYSQL_ASSOC);

            }

            // count rows

            function countRows(){

                        if(!$rows=mysql_num_rows($this->result)){

                                   $this->mysql->isError(‘Error counting rows’);

                        }

                        return $rows;

            }

            // count affected rows

            function countAffectedRows(){

                        if(!$rows=mysql_affected_rows($this->mysql->conId)){

                                   $this->mysql->isError(‘Error counting affected rows’);

                        }

                        return $rows;

            }

            // get ID from last inserted row

            function getInsertID(){

                        if(!$id=mysql_insert_id($this->mysql->conId)){

                                   $this->mysql->isError(‘Error getting ID’);

                        }

                        return $id;

            }

            // seek row

            function seekRow($row=0){

                        if(!mysql_data_seek($this->result,$row)){

                                   $this->mysql->isError(‘Error seeking row’);

                        }

            }

}

Our brand new “Result” class behaves in a simple manner, and its constructor takes two parameters (remember how it was created within the “MySQLConnector” class). The first parameter &$mysql, is a reference of a “MySQLConnector” object, in order to provide database connectivity, and the second, $result is the result set obtained after performing the query. Once passed, they’re assigned as class data members.

The rest of the methods are pretty easy to follow, as you’ll probably agree. The “fetchRow()” method is used to return a row from the result set, as we’ve probably seen hundreds of times.

To provide the class with the ability to count rows, I’ve defined the “countRows()” method, which simply retrieves the number of rows returned by the query. This might be useful for a paging class or other system that needs to find out the total number of rows.

Okay, now hold on your breath a little longer until we’ve seen the rest of the class methods.

The next remaining methods are “countAffectedRows()”, handy for finding out how many rows were affected by an INSERT, UPDATE or DELETE SQL statement; “getInsertID()”, which retrieves the ID of an AUTO_INCREMENT field, after an insertion operation; and finally “seekRow(), that places the pointer at a specified position within the result set. As you might guess, I’ve added to the class the most common operations associated with MySQL. However, you might add to it your own methods to extend its functionality.

Notice that each method handles an error condition by calling directly the “isError()’ method, provided by “MySQLConnector” class, like this:

$this->mysql->isError(‘Error getting ID’);

As you can appreciate, “isError()” is invoked by all of the methods, providing a centralized mechanism to handle errors. One possible improvement would be writing a method that degrades the application gracefully when an error occurs, instead of displaying ugly messages.

At this time, we’ve finished defining our “Result” class, so we’re ready to implement the classes. Just keep reading to find out how they’re used in a PHP application.

{mospagebreak title=Assembling the whole picture: putting the classes to work}

Having explained in detail the features of each class, it would be pretty didactical to show how we can take advantage of their abilities, emphasizing strongly the aspects inherent to Web-related tasks. Therefore, let’s start out by demonstrating the way we can connect to MySQL and retrieve some database records. The code is the following:

// include class files

require_once ‘mysqlclass.php';

require_once ‘resultclass.php';

// instantiate a MySQLConnector object

$options=array(‘host’=>’localhost’,’user’=>’user’,’password’=>’password’,
‘database’=>’articles’);

$db=&new MySQLConnector($options);

// build query

$sql=’SELECT name,site FROM articles';

// instantiate a resultSet object

$result=$db->performQuery($sql);

// display results

while($row=$result->fetchRow()){

            echo $row['name'].’&nbsp;’.$row['site'].'<br />';

}

// display total number of records

echo ‘Total number of articles : ‘.$result->countRows(). ‘<br />';

In the above snippet, we’ve included the class files. Then, we’ve instantiated a “MySQLConnector” object and performed the connection to the server, passing the proper parameters, in this case selecting a sample database.

Once the connection is established, we build a simple query to get some records from an “articles” database table. Notice the usage of the “fetchRow()” method belonging to the “Result” class, for fetching the records and display the results on the browser. Undoubtedly, taking a look at each line of code, we can clearly see what’s happening in every instance.

Besides, we use “countRows()” to display the total number of articles returned by the query. Very simple, eh?

Okay, let’s go one step forward and add a record to the database table, like this:

// include class files

require_once ‘mysqlclass.php';

require_once ‘resultclass.php';

// instantiate a MySQLConnector object

$options=array(‘host’=>’localhost’,’user’=>’user’,’password’=>’password’,
‘database’=>’articles’);

$db=&new MySQLConnector($options);

// build query

$sql=”INSERT INTO articles SET name=’Building a Template Parser class with PHP – Part 3′,site=’Devshed.com'”;

// insert new row

$result=$db->performQuery($sql);

// display information about last record inserted

echo ‘Data from the last record inserted:<br />';

$sql=”SELECT * FROM articles WHERE articleid='”.$result->getInsertID().”‘”;

$result=$db->performQuery($sql);

$row=$result->fetchRow();

echo $row['articleid'].$row['name'].$row['site'];

In this example, we insert a new article into the “articles” database table, and next we display some information about the last entry, using the “getInsertID()” method, as listed below:

$sql=”SELECT * FROM articles WHERE articleid='”.$result->getInsertID().”‘”;

Finally, we perform the query, showing the data associated with the article:

echo $row['articleid'].$row['name'].$row['site'];

Now, let’s update an specific record within the “articles” table, using again the provided methods:

// include class files

require_once ‘mysqlclass.php';

require_once ‘resultclass.php';

// instantiate a MySQLConnector object

$options=array(‘host’=>’localhost’,’user’=>’user’,’password’=>’password’,
‘database’=>’articles’);

$db=&new MySQLConnector($options);

// build query

$sql=”SELECT * FROM articles WHERE name=’Building a Template Parser class with PHP – Part 1′”;

// perform query

$result=$db->performQuery($sql);

$row=$result->fetchRow();

// build query

$sql=”UPDATE articles SET name=’Building a Template Parser class with PHP – Part 3′,site=’Devshed.com’ WHERE articleid='”.$row['articleid'].”‘”;

// perform query

$db->performQuery($sql);

In this case, we update a particular database record in a two-step sequence. The first step performs a SELECT statement to return the row that we want to be updated. Once we’ve gathered the row’s ID , we use it to perform the UPDATE query, in this way updating the specific record. Of course, the same operation might be carried out with a single SQL UPDATE statement, but here we’re demonstrating the clear use of both classes.

Lastly, let’s complete the trip, by deleting a database record. The process is as simple as this:

// include class files

require_once ‘mysqlclass.php';

require_once ‘resultclass.php';

// instantiate a MySQLConnector object

$options=array(‘host’=>’localhost’,’user’=>’user’,’password’=>’password’,
‘database’=>’articles’);

$db=&new MySQLConnector($options);

// build query

$sql=”DELETE FROM articles WHERE name=’Building a Template Parser class with PHP – Part 3′”;

// perform query

$db->performQuery($sql);

In a similar way, we delete a specific row from the database table. However, as applicable to UPDATE statements, don’t ever forget to add a WHERE clause to the query. Otherwise you’ll delete all of the rows from your carefully crafted table!

Well, I think that our examples are more than enough to demonstrate the flexibility and power that composition offers to developers. Just compare the above code with a procedural approximation, and surely you’ll see the benefits of packaging all of the internal processing to make the connections, execute queries, format results, handle errors, in a set of classes that do the hard work “behind the scenes.” Definitely, this approach is something that must be strongly considered.

Conclusion

In this series, we’ve gone over the basics of composition in PHP, in order to illustrate with copious examples its capability in several situations. While this is not meant to say that every possible project should be conceived for being set up using classes, as websites evolve to more complex applications, the object-oriented schema has proven to be a lot more efficient. So, you have the background, the tools and that pinch of willpower to implement a wealth of OOP resources in your projects. Trust me, you won’t be disappointed. 

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