Page 1 of 1

Maintain a single DB object (singleton pattern?)

Posted: Mon Sep 07, 2009 2:36 am
by lorenzo-s
I'm coding a DB class to manage all the MySQL operations. In my projects I need to use a single object of this class to query the database. My problem is the "visibility" of the DB object variable, that is:

Code: Select all

// Create DB object
$db = new DB();
 
// Here I can use the global variable
$db->query("SELECT * FROM table");
 
// But inside a function or a class method
function my_function() {
    // Here $db is obviously not visible! :(
} 
A (bad) solution can be using global $db inside the functions, bad if I change the variable name... A (good) solution seems to be the singleton pattern:
http://www.ultramegatech.com/blog/2009/ ... n-pattern/
I have made a similar thing:

Code: Select all

class DB() {
 
    private static $last_db = null;
 
    public function __construct() {
        // mysql_connect(); etc...
        self::$last_db = $this; // store last object created
    }
 
    public static function get() {
        if (is_null(self::$last_db)) throw new Exception('DB: no database opened');
        return self::$last_db;
    }
 
}
 
// And now in my functions I can do
function my_function() {
    $db = DB::get();
    $db->query("SELECT * FROM table");
}
Is there a better solution? Maybe that don't need an instruction ($db = DB::get()) at the beginning of every function? How do you do in this cases? :mrgreen:
Thank you all...

Re: Maintain a single DB object (singleton pattern?)

Posted: Mon Sep 07, 2009 2:58 am
by requinix
You do see there's a flaw in the logic, right? You have to create a new DB before you can use ::get and that kind defeats the whole Singleton idea.

Here's a slightly different version.

Code: Select all

class DB() {
 
    private static $last_db = null;
 
    private function __construct() {
        // mysql_connect(); etc...
    }
 
    public static function get() {
        if (is_null(self::$last_db)) self::$last_db = new DB();
        return self::$last_db;
    }
 
}
 
// And now in my functions I can do
function my_function() {
    $db = DB::get();
    $db->query("SELECT * FROM table");
}
Note how
1. The constructor is private so only the DB class can create new instances.
2. It does not manipulate $last_db.
3. ::get is where the Singleton magic happens.

You do need a DB::get every time you need the database, but in classes you can simply things a little:

Code: Select all

class Foo {
 
    private $db = null;
 
    public function __construct() {
        $this->db = DB::get();
        // ...
    }
 
    public function bar() {
        // no need for DB::get() - just use $this->db
    }
 
}

Re: Maintain a single DB object (singleton pattern?)

Posted: Mon Sep 07, 2009 3:13 am
by lorenzo-s
About the first note, yes, you have right :) Searching the web, I read some articles and I note my error.
And the solution about the use of $db in classes is perfect. Exactly the workaround that I need 8) Thank you!