tags:

views:

83

answers:

3

I want to create a PDO class for handling data base connections.

Here is what I have:

require('php/packages/store/store_db_settings.php');

class store_pdo
{
    private $DBH; // Data Base Handler

    function __construct() 
    {
        $DBH = new PDO(DB_DSN,DB_USER,DB_PASSWORD);
    }

    public function getHandler()
    {
        return $DBH;
    }

}

I think this seems ok, however I am used to just using things like mysql_query and not really sure what problems I could run into in the future. So I thought the experience here could offer guidance.

Is what I have sufficient? should I make my class Singleton, or use static functions? Is there a best practice?

I don't want to go with this, then I after have several other classes using it, discover that I should have written it differently.

P.S. I just noticed that the best-practices tag is no longer allowed... does that mean questions like this are discouraged now too?

+3  A: 

A Singleton and a static class would both work fine. I can't think of a situation when it would make a difference.

Make sure that if there ever may be the possibility of using multiple connections, you make your Singleton/Static class multi-connection capable from the start (using an array of connections, or object properties...)

It could be argued, though, that all these methods create a "God Object" of some sort, are nothing but a glorified global, and go against the principles of real OOP. I asked a question about this once that yielded a lot of great feedback.

Pekka
Thanks, your second paragraph was my biggest concern in the back of my head, I am not sure why I would ever need to, but I have ended up doing things many times that I never thought I would need to. I am not really sure how I would go about making it multi-connection capable... and this may be subjective and unanswerable, but if I added it now is this a case of yagni or does yagni not really apply in this scenario? Thanks for your insights!
John Isaacks
@John it may be that you in fact aren't going to need it, but in this case, I would advocate creating provisions for it from the start anyway. Otherwise, you would have to do refactoring if you turn out to need it later. If you use a static or singleton, I would create a function that returns a PDO connection from an internal array: `DB::getConnection(1)->query(....)` - if `getConnection()` has no parameter, give back the default (first) connection. That is not very obtrusive, but gives you maximum flexibility.
Pekka
makes perfect since, thanks.
John Isaacks
+2  A: 

extend PDO to get you better control over it.

class Database Extends PDO
{
    static $instance; //singleton
    static function Singleton($params = false)
    {
       if(!isset(self::$instance))
       {
           self::$instance = new self($params); //tomh
           self::$instance->init();
       }
       return self::$instance;
    }
    private function __construct(){}; //not allowed with singleton.

    public function init($params) //Override PDO::__construct()
    {
       parent::__construct($params);
    }

    public function query($query)
    {
        //Catch,Custom Query Object maybe. W.e
        return parent::query($modified_query);
    }
}

Usage:

$Database = Database::Singleton(array('user' => 'root')); //....
$Database->query('Helooooooo Sexy MySql, Send me my Shizzle');
RobertPitt
This is a nice idea, but I think he wants to be able to access the object from anywhere - it sounds like that is his main issue.
Pekka
then add singleton ?
RobertPitt
http://stackoverflow.com/questions/3237562/implement-a-php-singleton-static-class-properties-or-static-method-variables/3237897#3237897
RobertPitt
+1  A: 

Singleton will bite you in the ass the first time you need to connect to two different databases, either for replication or two different databases. Then your code is so messed up.

Instead, utilize a single static function to easily load the last used configuration:

class MyPDODB extends PDO
{
    // Prevent unconfigured PDO instances!
    private function __construct($config)
    {
        $dsn = sprintf('mysql:dbname=%s;host=%s;port=%d;', $config['database'], $config['hostname'], $config['port']);
        parent::__construct($dsn, $config['username'], $config['password']);        
    }

    public static function loadDB($config_in = null)
    {
        static $last_config = null;

        if (!is_null($config_in))
        {
            self::validateConfig($config_in);
            $config = $config_in;
            if (!isset($config['isTemp']) || $config['isTemp'] !== true)
            {
                $last_config = $config;
            }
        }
        else
        {
            if (!is_null($last_config)) { $config = $last_config; }
            else throw new MyDBException("No config provided');
        }

        return new MyPDODB($config);
    }
}

In any function, you just do:

$db = MyPDODB::loadDB();
$db->prepare($sql);
$db->execute();

Easy, huh?

I spent a lot of time on this, please vote up ;-)

hopeseekr
two questions: 1. doesn't this mean you end up reconnecting to the database in every function call? 2. when using more than one db here, to ensure you have a connection to the correct db wouldn't you have to pass some config to loadDB() every time?
Tom Haigh
I left out a lot of code. It's an entire library I've made that's open sourced to members of phpexperts.pro.In short, no, it doesn't reconnect every function call. PHP's PDO caches connection attempts; it's smart enough to realize that if you connect to one particular PDO DB high in the stack, that it just uses that resource handle later in the stack. It's the same w/ every PHP DB library, afaik.As far as finding the correct DB each time... Look, if you're not wanting to change the global DB, you set the param $config['isTemp'] = true and it only uses that config for that instance.
hopeseekr