I have a section of code that depending on the URL requested, will include one of fourteen other files. Some of these fourteen files require a connection to one of three di
function &get_pdo()
{
static $_PDO = null;
if ($_PDO === null)
{
$_PDO = new PDO('your DSN', 'username', 'password');
}
return $_PDO;
}
Then you just do
$stmt = get_pdo()->prepare('...');
You could do the same by extending the PDO class and adding a static singleton function to it. I find this approach simplier. Also gives you the opportunity to call it from anywhere on the stack without having to put your connection in the arguments (which can be good or bad, depending on the situation).
I took another approach using __call magic method so you don't need to create individual wrappers for every method.
class PDOLazyConnector
{
private $dsn;
private $username;
private $password;
private $driver_options;
private $dbh;
public function __construct ($dsn, $username, $password, $driver_options = array ())
{
$this->dsn = $dsn;
$this->username = $username;
$this->password = $password;
$this->driver_options = $driver_options;
}
public function __call ($function, $args)
{
// connect to db (first time only)
$this->__init_dbh ();
// invoke the original method
return call_user_func_array (array($this->dbh, $function), $args);
}
public function __get ($property)
{
return $this->dbh->$property;
}
private function __init_dbh ()
{
// If db handler is not open yet, do it now
if (empty ($this->dbh)) {
$this->dbh = new PDO ($this->dsn, $this->username, $this->password, $this->driver_options);
}
}
}
You just have to replace your PDO instancing with PDOLazyConnector, so:
$dbh = new PDO($dsn, $user, $password, $driver_options);
with:
$dbh = new PDOLazyConnector($dsn, $user, $password, $driver_options);
PDO has an option for persistent connections PDO::ATTR_PERSISTENT.
See the comments in http://php.net/manual/en/book.pdo.php
This is the right idea, but not the best implementation of it.
Wrapping the SQL operations is good. But why don't you do it this way:
class Wrapper {
private static $db;
public static function someQuery() {
$db = self::getDatabase();
// now go on to execute the query
}
private static function getDatabase() {
if (self::$db === null) {
self::$db = // connect here
}
return self::$db;
}
}
This has a lot of advantages:
In your specific case, you should probably go with 3 separate Wrapper
classes. Putting everything into one class is doable (three different $db
variables) but probably more confusing than it's worth.
Use this class exactly how you would use the PDO
class.
class DB extends PDO {
protected $_config = array();
protected $_connected = false;
public function __construct($dsn, $user = null, $pass = null, $options = null) {
//Save connection details for later
$this->_config = array(
'dsn' => $dsn,
'user' => $user,
'pass' => $pass,
'options' => $options
);
}
public function checkConnection() {
if (!$this->_connected) {
extract($this->_config);
parent::__construct($dsn, $user, $pass, $options)
$this->_connected = true;
}
}
public function query($query) {
$this->checkConnection();
return parent::query($query);
}
public function exec($query) {
$this->checkConnection();
return parent::exec($query);
}
//etc.
}