TalkPHP
 
 
Account Login
Latest Articles
» The basic usage of PHPTAL, a XML/XHTML template library for PHP
» Vulnerable methods and the areas they are commonly trusted in.
» Simple way to protect a form from bot
» The Basics On: How Session Stealing Works
» How to keep your forms from double posting data
IRC Channel
IRC Speech Bubble Join the friendly bunch on IRC...
(#TalkPHP on Freenode)

...Also available via a web interface.

See this thread for information on the TalkPHP Free Hugs Initiative™. Subject to availability.
Associates
Associates
CSS Tutorials
Reply
 
LinkBack Thread Tools Search this Thread Display Modes
Old 04-28-2009, 04:27 PM   #1 (permalink)
The Acquainted
 
Join Date: Oct 2007
Posts: 170
Thanks: 18
maZtah is an unknown quantity at this point
Default Singleton PDO Database class, tips/suggestions?

Hi all,

This is a singleton PDO Database class I wrote. Do you have any tips/suggestions?

PHP Code:
<?php

class Database
{
    private static 
$m_pInstance NULL;
    private 
$m_pConn;
    
    private function 
__construct() {
        
$this->connect('hostname''username''password''database');
    }
    
    private function 
__clone() { }
    
    public static function 
get_instance()
    {
        if (!
self::$m_pInstance)
        {
            
self::$m_pInstance = new Database();
        }
        
        return 
self::$m_pInstance;
    }
    
    public function 
connect($szHostname$szUsername$szPassword$szDatabase)
    {
        try
        {
            
$this->m_pConn = new PDO('mysql:host='.$szHostname.';dbname='.$szDatabase$szUsername$szPassword);
                        
            
$this->m_pConn->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
        }
        catch(
PDOException $e)
        {
            echo 
$e->getMessage();
        }
    }
    
    public function 
query($szQuery)
    {
        
$pStatement $this->m_pConn->prepare($szQuery);
        
$pStatement->execute();
        
        
$aResult $pStatement->fetchAll();
        
        return 
$aResult;
    }
    
    public function 
query_row($szQuery)
    {
        
$aResult $this->query($szQuery);
        
        return 
$aResult[0];
    }
    
    public function 
query_column($szQuery)
    {
        
$aResult $this->query_row($szQuery);
        
        return 
$aResult[0];
    }
    
    public function 
insert($szQuery)
    {
        
$iCount $this->m_pConn->exec($szQuery);
        
        return 
$iCount;
    }
}

?>
maZtah is offline  
Reply With Quote
Old 05-04-2009, 08:27 AM   #2 (permalink)
Jim
The Addict
 
Jim's Avatar
 
Join Date: Nov 2007
Location: the Netherlands
Posts: 281
Thanks: 2
Jim is on a distinguished road
Default

PDO is nice but I personally would go for a Singleton/Factory.

The class looks pretty nice though :)
__________________
Nunchaku! Who doesn't like martial arts? =)
Send a message via MSN to Jim Send a message via Skype™ to Jim
Jim is offline  
Reply With Quote
Old 05-18-2009, 03:33 PM   #3 (permalink)
The Acquainted
 
Join Date: Oct 2007
Posts: 170
Thanks: 18
maZtah is an unknown quantity at this point
Default

I've made a little update to the database class, here it is:

Again, tips and suggestions are more than welcome!

PHP Code:
<?php

class Database
{
    private static 
$m_pInstance;
    private 
$m_pConn;
    
    private function 
__construct()
    {
        if (
LOCAL)
        {
            
$this->connect('localhost''username''password''database');
        }
        else
        {
            
$this->connect('localhost''username''password''database');
        }
    }
    
    private function 
__clone() { }
    
    public static function 
get_instance()
    {
        if (!
self::$m_pInstance)
        {
            
self::$m_pInstance = new Database();
        }
        
        return 
self::$m_pInstance;
    }
    
    public function 
connect($szHostname$szUsername$szPassword$szDatabase)
    {
        try
        {
            
$this->m_pConn = new PDO('mysql:host='.$szHostname.';dbname='.$szDatabase$szUsername$szPassword);
            
            if (
LOCAL)
            {
                
$this->m_pConn->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
            }
            else
            {
                
$this->m_pConn->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_SILENT);
            }
        }
        catch (
PDOException $e)
        {
            echo 
$e->getMessage();
        }
    }
    
    public function 
query($szQuery)
    {
        
$pStatement $this->m_pConn->prepare($szQuery);
        
$pStatement->execute();
        
        
$aResult $pStatement->fetchAll();
        
        return 
$aResult;
    }
    
    public function 
select_query($szTable$aFields$aWhere NULL$aOrderBy NULL$aLimit NULL)
    {
        
$szQuery 'SELECT ';
        
        
$szQuery .= implode(', ',$aFields);
        
$szQuery .= ' FROM '.$szTable;
        
        if (
is_array($aWhere))
        {
            
$szWhere '';
            
            foreach(
$aWhere as $szKey => $szValue)
            {
                if (!
is_numeric($szValue))
                {
                    
$szValue "'".$szValue."'";
                }
                
$szWhere .= ' '.$szKey.' = '.$szValue.' AND';
            }
            
            
$szWhere rtrim($szWhere'AND');
            
            
$szQuery .= ' WHERE '.$szWhere;
        }
        
        if (
is_array($aOrderBy))
        {
            
$szOrderBy '';
            
            foreach(
$aOrderBy as $szKey => $szValue)
            {
                
$szOrderBy .= ' '.$szKey.' '.$szValue.',';
            }
        
            
$szOrderBy rtrim($szOrderBy',');
            
            
$szQuery .= ' ORDER BY '.$szOrderBy;
        }
        
        if (
$aLimit !== NULL)
        {
            
$szLimit implode(','$aLimit);
            
$szQuery .= ' LIMIT '.$szLimit;
        }
        
        return 
$this->query($szQuery);
    }
    
    public function 
select_query_row($szTable$aFields$aWhere NULL$aOrderBy NULL$aLimit NULL)
    {
        
$aResult $this->select_query($szTable$aFields$aWhere$aOrderBy$aLimit);
        
        return (isset(
$aResult[0]) ? $aResult[0] : FALSE);
    }
    
    public function 
select_query_column($szTable$aFields$aWhere NULL$aOrderBy NULL$aLimit NULL)
    {
        
$aResult $this->select_query_row($szTable$aFields$aWhere$aOrderBy$aLimit);
        
        return (isset(
$aResult[0]) ? $aResult[0] : FALSE);
    }
    
    public function 
insert_query($szTable$aFields$aValues)
    {
        
$szQuery 'INSERT INTO '.$szTable.' (';
        
$szQuery .= implode(', ',$aFields);
        
$szQuery .= ') VALUES';
        
        foreach (
$aValues as $aValue)
        {
            
$aValue array_map(array($this'clean_input'), $aValue);
            
            
$szQuery .= ' (';
            
$szQuery .= implode(', ',$aValue);
            
            
$szQuery rtrim($szQuery',');
            
$szQuery .= '),';
        }
        
        
$szQuery rtrim($szQuery',');
        
        
$iCount $this->m_pConn->exec($szQuery);
        
        return 
$iCount;
    }
    
    private static function 
clean_input($mInput)
    {
        if (
is_numeric($mInput))
        {
            return 
$mInput;
        }
        else
        {
            return 
"'".$mInput."'";
        }
    }
}

?>
maZtah is offline  
Reply With Quote
Old 05-18-2009, 03:44 PM   #4 (permalink)
La Vida es Sueño
Advanced Programmer Top Contributor 
 
Wildhoney's Avatar
 
Join Date: Sep 2007
Location: Oldham
Posts: 2,280
Thanks: 90
Wildhoney is on a distinguished road
Default

Where is LOCAL defined and why do we have an empty __clone method?
__________________
The man who comes back through the Door in the Wall will never be quite the same as the man who went out.
Send a message via AIM to Wildhoney Send a message via MSN to Wildhoney Send a message via Yahoo to Wildhoney
Wildhoney is offline  
Reply With Quote
Old 05-18-2009, 04:43 PM   #5 (permalink)
The Frequenter
Newcomer 
 
xenon's Avatar
 
Join Date: Dec 2007
Location: Bucharest, Romania
Posts: 438
Thanks: 3
xenon is on a distinguished road
Default

Quote:
Originally Posted by Wildhoney View Post
Where is LOCAL defined and why do we have an empty __clone method?
I don't see either where that LOCAL constant was defined...supposedly in another file, which kind of breaks the OO paradigm. Instead, you should have a private member in your class (called $env or such), and a getter/setter method for that. That way, your class will be entirely decoupled from the rest of the application (and you wouldn't need to define a LOCAL constant in all your scripts - not doing so throws a warning).

As for the private __clone method, that's a common thing (I do it myself), and it's good combined with the singleton pattern. Trying to clone the object returned by the getInstance() method will be permitted (thus breaking the singleton rules), as long as you don't define the __clone method as private

I don't agree though with the public connect function. Calling that method several times will only recreate the connection to the DB. You'd probably want to extend the actual PDO class and transform it into a singleton from within your class.
__________________
I have optimistic thoughts, even though sometimes (if not always) life's a bitch.
xenon is offline  
Reply With Quote
Old 05-18-2009, 08:36 PM   #6 (permalink)
The Acquainted
 
Join Date: Oct 2007
Posts: 170
Thanks: 18
maZtah is an unknown quantity at this point
Default

Thanks for the feedback. The first file which gets loaded is init.php:

PHP Code:
<?php
// Check if we are local
if ($_SERVER['SERVER_ADDR'] == '127.0.0.1')
{
    
define('LOCAL'TRUE);
}
else
{
    
define('LOCAL'FALSE);
}

// Activate error reporting on local server
if (LOCAL)
{
    
error_reporting(E_ALL);
}

// Include the main functions
include_once('library.php');

// Load mandatory class(es)
include_once('database.class.php');

// Prepare for autoloading the appropriate classes
function __autoload($szClass)
{
    include_once(
strtolower($szClass).'.class.php');
}

// Set locale to Dutch
setlocale(LC_ALL'nl_NL');

// Define the Google Maps API key
define('GMAPS_KEY', (LOCAL 'ABQIAAAAXRbN4TY9xbY5dw4fbMiPVRQQjDJwdt1aUvnAUED1_0C4Ozpy2hTgmlZavSPTSh4PGmg3dWXDWR79mw' 'ABQIAAAAXRbN4TY9xbY5dw4fbMiPVRR9LNncnZ2GbBrTPZVxzPxSqrkWtRSSZ078PFurHFpxZZ3lovXlkZukJg'));

// Get the main menu
$aMainMenu Database::get_instance()->select_query('menu', array('id''name''href'), array('parent_id' => 0), array('rank' => 'ASC'));

// Get the weather details
$pWeather = new Weather();

?>
I just made the connect() function private. I will also add a getter/setter to the class instead of relying on a defined global.

Thanks!
maZtah is offline  
Reply With Quote
Old 05-20-2009, 10:04 AM   #7 (permalink)
The Acquainted
 
Join Date: Oct 2007
Posts: 170
Thanks: 18
maZtah is an unknown quantity at this point
Default

What I did now instead of the global defined LOCAL variable, I made a Registry class where I save global variables. Then i pass the Registry class to every other class which might need the global variables.

In my init.php file:

php Code:
// Load the registry
$pRegistry = new Registry();

// Check if we are local
if ($_SERVER['SERVER_ADDR'] == '127.0.0.1')
{
    $pRegistry->is_local = TRUE;
}
else
{
    $pRegistry->is_local = FALSE;
}

// Load database with the Registry settings
$pRegistry->m_pDatabase = Database::get_instance($pRegistry);

And then my Database class looks like:

php Code:
<?php

class Database
{
    private static $m_pInstance;
    private $m_pConn;
    private $m_pRegistry;
   
    private function __construct(Registry $pRegistry)
    {
        $this->m_pRegistry = $pRegistry;
       
        if ($this->m_pRegistry->is_local)
        {
            $this->connect('hostname', 'username', 'password', 'database');
        }
        else
        {
            $this->connect('hostname', 'username', 'password', 'database');
        }
    }
   
    private function __clone() { }
   
    public static function get_instance(Registry $pRegistry = NULL)
    {
        if (!self::$m_pInstance)
        {
            self::$m_pInstance = new Database($pRegistry);
        }
       
        return self::$m_pInstance;
    }
   
    private function connect($szHostname, $szUsername, $szPassword, $szDatabase)
    {
        try
        {
            $this->m_pConn = new PDO('mysql:host='.$szHostname.';dbname='.$szDatabase, $szUsername, $szPassword);
           
            if ($this->m_pRegistry->is_local)
            {
                $this->m_pConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            }
            else
            {
                $this->m_pConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
            }
        }
        catch (PDOException $e)
        {
            echo $e->getMessage();
        }
    }
   
    public function query($szQuery)
    {
        $pStatement = $this->m_pConn->prepare($szQuery);
        $pStatement->execute();
       
        $aResult = $pStatement->fetchAll();
       
        return $aResult;
    }
   
    public function select_query($szTable, $aFields, $aWhere = NULL, $aOrderBy = NULL, $aLimit = NULL)
    {
        $szQuery = 'SELECT ';
       
        $szQuery .= implode(', ',$aFields);
        $szQuery .= ' FROM '.$szTable;
       
        if (is_array($aWhere))
        {
            $szWhere = '';
           
            foreach($aWhere as $szKey => $szValue)
            {
                if (!is_numeric($szValue))
                {
                    $szValue = "'".$szValue."'";
                }
                $szWhere .= ' '.$szKey.' = '.$szValue.' AND';
            }
           
            $szWhere = rtrim($szWhere, 'AND');
           
            $szQuery .= ' WHERE '.$szWhere;
        }
       
        if (is_array($aOrderBy))
        {
            $szOrderBy = '';
           
            foreach($aOrderBy as $szKey => $szValue)
            {
                $szOrderBy .= ' '.$szKey.' '.$szValue.',';
            }
       
            $szOrderBy = rtrim($szOrderBy, ',');
           
            $szQuery .= ' ORDER BY '.$szOrderBy;
        }
       
        if ($aLimit !== NULL)
        {
            $szLimit = implode(',', $aLimit);
            $szQuery .= ' LIMIT '.$szLimit;
        }
       
        return $this->query($szQuery);
    }
   
    public function select_query_row($szTable, $aFields, $aWhere = NULL, $aOrderBy = NULL, $aLimit = NULL)
    {
        $aResult = $this->select_query($szTable, $aFields, $aWhere, $aOrderBy, $aLimit);
       
        return (isset($aResult[0]) ? $aResult[0] : FALSE);
    }
   
    public function select_query_column($szTable, $aFields, $aWhere = NULL, $aOrderBy = NULL, $aLimit = NULL)
    {
        $aResult = $this->select_query_row($szTable, $aFields, $aWhere, $aOrderBy, $aLimit);
       
        return (isset($aResult[0]) ? $aResult[0] : FALSE);
    }
   
    public function insert_query($szTable, $aFields, $aValues)
    {
        $szQuery = 'INSERT INTO '.$szTable.' (';
        $szQuery .= implode(', ',$aFields);
        $szQuery .= ') VALUES';
       
        foreach ($aValues as $aValue)
        {
            $aValue = array_map(array($this, 'clean_input'), $aValue);
           
            $szQuery .= ' (';
            $szQuery .= implode(', ',$aValue);
           
            $szQuery = rtrim($szQuery, ',');
            $szQuery .= '),';
        }
       
        $szQuery = rtrim($szQuery, ',');
       
        $iCount = $this->m_pConn->exec($szQuery);
       
        return $iCount;
    }
   
    private static function clean_input($mInput)
    {
        if (is_numeric($mInput))
        {
            return $mInput;
        }
        else
        {
            return "'".$mInput."'";
        }
    }
}

?>

Any tips/suggestions on this way of doing things?
maZtah is offline  
Reply With Quote
Reply



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

Similar Threads
Thread Thread Starter Forum Replies Last Post
How to use the Singleton design pattern Karl Advanced PHP Programming 27 10-22-2012 08:16 AM
Using the factory pattern (mad rantings of a mind without coffee) sketchMedia Advanced PHP Programming 35 09-25-2009 11:05 AM
[Tutorial] How to organize your classes | Part 1 Tanax Advanced PHP Programming 10 03-01-2009 10:08 PM
A Generic Singleton Base Class Theo Advanced PHP Programming 7 08-18-2008 02:25 AM
A single(ton) child amongst us... delayedinsanity Advanced PHP Programming 6 04-27-2008 04:37 PM


All times are GMT. The time now is 01:52 AM.

 
     

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0
Inactive Reminders By Icora Web Design