View Single Post
Old 10-20-2007, 08:19 PM   #1 (permalink)
sketchMedia
The Prestige
Advanced Programmer Top Contributor Good Samaritan 
 
sketchMedia's Avatar
 
Join Date: Oct 2007
Location: Manchester, UK
Posts: 854
Thanks: 32
sketchMedia is on a distinguished road
Big Grin Using the factory pattern (mad rantings of a mind without coffee)

Yo,

This is my first tutorial of sorts, i came across this method of doing things a few months ago when i needed some form of database abstraction. This is what i came up with (albeit this version is greatly stripped down to its core so that it will show the workings better), if you have any improvements to this method or if there are any better ways of doing it i'm open to ideas :) .

The first point I'd like to make is the use of an interface in this script, its important to understand that i needed a database abstraction class and the interface allows me to specify which methods a class must implement, therefore i can have a mysql class and a mssql class, both must have the same methods so that the rest of the system will work the same when i decide i want to change over from mysql to mssql.

For example i have a class called mysql, it has a method called query() for sending querys to the database, and i have used it in my system extensively, then i decide i don't want to use mysql anymore and i want to switch over the mssql. The new mssql class i code also has a query method, but without thinking i call it doQuery() or something, now the rest of the system where the method query() was called will fail. The interface allows you to apply a kind of rule to the class, so if i tried naming a method doQuery() and in the interface it said that it must have a query() method, PHP will throw an error and more importantly i don't have to go through hundreds of lines of code changing names of method calls.

with that hopefully explained i can get on (hopefully)

Right, i will be combining two patterns here really, the database object is instantiated with a factory pattern but the database object is singleton.

here is the database classes and interface:

PHP Code:
interface DB
{
    public function 
connect();
    public function 
query();
    public function 
disconnect();
}

class 
DBmysql implements DB
{
    public function 
connect()
    {
        
//database connection stuff
    
}
    public function 
query()
    {
        
//perform database query stuff
    
}
    public function 
disconnect()
    {
        
//disconnect database
    
}
}

class 
DBmssql implements DB
{
    public function 
connect()
    {
        
//database connection stuff
    
}
    public function 
query()
    {
        
//perform database query stuff
    
}
    public function 
disconnect()
    {
        
//disconnect database
    
}

as you can see both classes 'implement' the interface meaning that they must conform with that interface (as they do).

now the factory class, this will determine the type of database that we want to use, then create the object for us:

PHP Code:
class DBfactory
{
    public static 
$pDB;

    public static function &
factory($szType "")
    {
        if(!
is_object(self::$pDB))
        {
            switch(
$szType)
            {
                case 
'mysql':
                    
self::$pDB = new DBmysql;
                    break;
                case 
'mssql':
                    
self::$pDB = new DBmssql;
                    break;
                default:
                    
self::$pDB = new DBmysql;
                    break;
            }
        }
        return 
self::$pDB;
    }

First thing to notice is that i have a static variable 'pDB' and as the naming convention should tell you, i'm going to be using this as an object pointer (well php reference to an object, as C pointers and PHP references are slightly different but thats out of the scope of this tutorial, they both do practically the same thing), its static because it needs to remain without having an instance of the object to be created, i'm assuming you know what a static is as this is in the advanced PHP forum :cool: .
This static allows us to make the database object a singleton (read karl's great tutorial on the singleton design pattern, if your not sure what im going on about:
How to use the Singleton design pattern).

Next i have a static method called factory, this is the method we call to create a database object, its static like the object pointer so that i don't actually have to have an instance of this class in order to use it, also at the start of the function name is the "&" symbol, this basically tells PHP the i will be returning a reference (returns by reference instead of by value).
The method has a string param 'szType' with a blank default value, this will be how we tell the class which database type we need, for this example i will be using mysql.

Next the string param goes into a switch but before it does it checks the static 'pDB' to see if there is already an object created, if there is just reuse that object, if there isn't it then creates the object from the correct class.

notice that because 'pDB' is static it isn't instantiated in the object, so $this-> wont work as we don't have a reference to the current object ($this is a reference to the calling object which is usually the object to which the method belongs although it can be others too)
thus we have to use the self keyword, along with the the Scope Resolution Operator "::" so that we can access the static variable 'pDB'.

Because we have a default value of szType (szType = "") if nothing is passed into the method, the switch will go to the default (saves you having to type the database type if the default is all you need) or alternatively you could have a named constant in config file or something.

right moving on, inside the switch (after it has determined the type, for example we have passed in the string 'mysql' into the param) it goes and creates an instance of the class 'DBmysql' then assigns the static variable 'pDB' with the reference to that object, then returns the reference of the reused/newly created object, out of the method.

To use this we could do this:
PHP Code:
$db DBfactory::factory("mysql");
$db->query(".."); 
or just use the default:
PHP Code:
$db DBfactory::factory();
$db->query(".."); 
We could alternitivly chain it all together (as discussed in another topic) this is my favourate way, it just makes it look nicer:
PHP Code:
DBfactory::factory()->query(".."); 
hope that made sense, right im off to drink alot of coffee now, im sure when i return and re-read this i will notice a whole load of incomprehensable and vomit inducing grammatical and general errors, thats the risk you take when you do something that requires your brain to be working without feeding it coffee beforehand.
(i appologise if its seems a bit jumbled and crazy, its just they way i am when i havent had my daily coffee to calm my brain down abit, so basicly this tutorial is a result of my coffee withdrawal insanity)

ciao for now
__________________
mysql> SELECT * FROM `users` WHERE `users`.`clue` > 0;
Empty set (0.00 sec)
sketchMedia is offline  
Reply With Quote
The Following 2 Users Say Thank You to sketchMedia For This Useful Post:
Alcar (01-17-2008), Tanax (01-23-2008)