William Jiang

JavaScript,PHP,Node,Perl,LAMP Web Developer – http://williamjxj.com; https://github.com/williamjxj?tab=repositories

Interfaces, Abstract Classes

PHP 5 OOP: Interfaces and Abstract Classes and the Adapter Pattern

Introduction

No matter like or not, PHP 5 owns as much as OOP features which Java has, such as Abstract or Interface. According to my experience, this is not common used in the developing. Classes, Object Inheritance seems enough for most case. But Interfaces, Abstract Classes are on a higher view. One usage is for database connectivity. It is able to connect to and talk to just about any database server or interface you can imagine. However, with this comes a few inherent problems; each database system has its own features, functions and in most cases they have their own versions of SQL. Although the functions used to access these databases are similar they do vary subtly meaning that if you were to want to port an application written for MySql to MS SQL server, the refactoring would require manually changing all calls to mysql_query() to mssql_query(). Here we can create a database abstraction layer similar to PEAR DB to hide all specific features of individual database and provide a united interface.

Abstract Classes

Class Abstraction PHP 5 introduces abstract classes and methods. It is not allowed to create an instance of a class that has been defined as abstract. Any class that contains at least one abstract method must also be abstract. Methods defined as abstract simply declare the method’s signature they cannot define the implementation. When inheriting from an abstract class, all methods marked abstract in the parent’s class declaration must be defined by the child; additionally, these methods must be defined with the same (or a less restricted) visibility. For example, if the abstract method is defined as protected, the function implementation must be defined as either protected or public, but not private.

List 1: Abstract class example

<?php
abstract class AbstractClass
{
    
// Force Extending class to define this method
    
abstract protected function getValue();
    abstract protected function 
prefixValue($prefix);

    // Common method
    
public function printOut() {
        print 
$this->getValue() . “\n”;
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function 
getValue() {
        return 
“ConcreteClass1”;
    }

    public function prefixValue($prefix) {
        return 
{$prefix}ConcreteClass1″;
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function 
getValue() {
        return 
“ConcreteClass2”;
    }

    public function prefixValue($prefix) {
        return 
{$prefix}ConcreteClass2″;
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo 
$class1->prefixValue(‘FOO_’) .“\n”;

$class2 = new ConcreteClass2;
$class2->printOut();
echo 
$class2->prefixValue(‘FOO_’) .“\n”;
?>

The above example will output:

ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

Interfaces

Object Interfaces

Object interfaces allow you to create code which specifies which methods a class must implement, without having to define how these methods are handled.

Interfaces are defined using the interface keyword, in the same way as a standard class, but without any of the methods having their contents defined.

All methods declared in an interface must be public, this is the nature of an interface.
implements

To implement an interface, the implements operator is used. All methods in the interface must be implemented within a class; failure to do so will result in a fatal error. Classes may implement more than one interface if desired by separating each interface with a comma.
Interfaces can be extended like classes using the extends operator.

List 2: Interface example

<?php

// Declare the interface ‘iTemplate’
interface iTemplate
{
    public function 
setVariable($name$var);
    public function 
getHtml($template);
}

// Implement the interface
// This will work
class Template implements iTemplate
{
    private 
$vars = array();
  
    public function 
setVariable($name$var)
    {
        
$this->vars[$name] = $var;
    }
  
    public function 
getHtml($template)
    {
        foreach(
$this->vars as $name => $value) {
            
$template str_replace(‘{‘ $name ‘}’$value$template);
        }
 
        return 
$template;
    }
}

// This will not work
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{
    private 
$vars = array();
  
    public function 
setVariable($name$var)
    {
        
$this->vars[$name] = $var;
    }
}
?>

An interface is similar to an abstract class; indeed interfaces occupy the same namespace as classes and abstract classes. For that reason, you cannot define an interface with the same name as a class. An interface is a fully abstract class; none of its methods are implemented and instead of a class sub-classing from it, it is said to implement that interface.

An interface will be used in the database abstraction layer you create. This ensures that every time you create a class for a particular database, the same API is exposed. When using an interface, you can then rely on the methods defined for the interface to be part of the class because, if they are not, PHP will not parse it.

The MySql functions will be used as an example because they are the most commonly used amongst PHP programmers. The most commonly used functions are:

  • mysql_connect()
  • mysql_error()
  • mysql_errno()
  • mysql_query()
  • mysql_fetch_array()
  • mysql_fetch_row()
  • mysql_fetch_assoc()
  • mysql_fetch_object()
  • mysql_num_rows()
  • mysql_close()

If all the database class APIs you create can expose the same methods with the same return types then you can be sure that changing from one database to another, such as from MySql to Postgre SQL, will be painless. As such, the interface in listing 3 can be determined for your API.

Listing 3: An Abstracted Database Interface

interface DB 
{ 
    public function connect(); 
    public function error(); 
    public function errno(); 
    public static function escape_string($string); 
    public function query($query); 
    public function fetch_array($result); 
    public function fetch_row($result); 
    public function fetch_assoc($result); 
    public function fetch_object($result); 
    public function num_rows($result); 
    public function close(); 
} 

Any class implementing the interface must define each method that is declared in the interface, and each method must have at least the parameters identified in their interface definitions. It may have more parameters as long as they are optional, but it cannot have less.

Look at a class in Listing 4 that implements the database interface. You should recall that I mentioned the adapter pattern earlier. This is an example of the adapter pattern, which is used by programmers in order to adapt one API. The API you are adapting from could be another object-based API or as being done here, an adaptation from a modular API.

Notice how the escape_string() method is included as a static method. This method does not require an active connection to a database and should not require and instance of any object which implements the DB interface. In my opinion, this is the single most important method of any database implementation; a poorly implemented escape string method could make your applications vulnerable SQL injection.

Listing 4: Implementing the database interface

class MySqlDB implements DB 
    { 
        private  $link; 
         
        public function connect($server='', $username='', $password='', $new_link=true, $client_flags=0) 
        { 
            $this->link = mysql_connect($server, $username, $password, $new_link, $client_flags); 
        } 
     
        public function errno() 
        { 
            return mysql_errno($this->link); 
        } 

        public function error() 
        { 
            return mysql_error($this->link); 
        } 

        public static function escape_string($string) 
        { 
            return mysql_real_escape_string($string); 
        } 

        public function query($query) 
        { 
            return mysql_query($query, $this->link); 
        } 
         
        public function fetch_array($result, $array_type = MYSQL_BOTH) 
        { 
            return mysql_fetch_array($result, $array_type); 
        } 

        public function fetch_row($result) 
        { 
            return mysql_fetch_row($result); 
        } 
         
        public function fetch_assoc($result) 
        { 
            return mysql_fetch_assoc($result); 
        } 
         
        public function fetch_object($result) 
        { 
            return mysql_fetch_object($result); 
        } 
         
        public function num_rows($result) 
        { 
            return mysql_num_rows($result); 
        } 
         
        public function close() 
        { 
            return mysql_close($this->link); 
        } 

You’ll notice that there are many more mysql functions than methods that are adapted in the interface in listing 3. However, this small subset of functions is sufficient to meet the needs of most applications requiring trivial data storage and retrieval. The additional functions can be implemented and I have done this in the attached example file, you may also choose to add additional functionality to the class and the interface.

Listing 5: Creating a database class

$db = new MySqlDb; 
    $db->connect('host', 'username', 'password'); 
    $db->query('use users'); // we could also use $db->select_db here but it is not consistent with the interface 

    $result = $db->query("SELECT username FROM users"); 
         
    while($row = $db->fetch_assoc($reuslt)) { 
        echo($row['username']); 
    } 

As shown in listing 5, you can now create a class for each database you want and as long as it implements the DB interface, switching from one to another is as easy as changing one line of code:

$db = new MsSqlDb; 

Conclusion

In this first article, you’ve seen how to create an abstraction layer to access a database. Using this, you saw how creating an interface helps you to isolate your application so that you can easily switch from one database to anther without rewriting your own applications.

4 responses to “Interfaces, Abstract Classes

  1. tabletki na odchudzanie 12/26/2010 at 10:30 pm

    It is always pleasure to read your articles, will back here soon

  2. powercashadvance.com 10/28/2011 at 9:22 am

    I wanted to inform you about how much we appreciate every little thing you’ve contributed to help increase the value of the lives of men and women in this subject material. Through your articles, we have gone via just an inexperienced to a skilled in the area. It truly is truly a gratitude to your efforts. Thanks

  3. yerba mate akcesoria 02/06/2013 at 2:59 am

    I like this weblog very much so much fantastic information.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: