Below I present three options for simplifying my database access when only a single connection is involved (this is often the case for the web apps I work on).
The general idea is to make the DB connection transparent, such that it connects the first time my script executes a query, and then it remains connected until the script terminates.
I'd like to know which one you think is the best and why. I don't know the names of any design patterns that these might fit so sorry for not using them. And if there's any better way of doing this with PHP5, please share.
To give a brief introduction: there is a DB_Connection class containing a query method. This is a third-party class which is out of my control and whose interface I've simplified for the purpose of this example. In each option I've also provided an example model for an imaginary DB "items" table to give some context.
Option 3 is the one that provides me with the interface I like most, but I don't think it's practical unfortunately.
I've described the pros and cons (that I can see) of each in the comment blocks below.
At the moment I lean towards Option 1 since the burden is put on my DB wrapper class instead of on the models.
All comments appreciated!
Note: For some reason the Stack Overflow preview is showing an encoded HTML entity instead of underscores. If the post comes through like that, please take this into account.
<?php
/**
* This is the 3rd-party DB interface I'm trying to wrap.
* I've simplified the interface to one method for this example.
*
* This class is used in each option below.
*/
class DB_Connection {
public function &query($sql) { }
}
/**
* OPTION 1
*
* Cons: Have to wrap every public DB_Connection method.
* Pros: The model code is simple.
*/
class DB {
private static $connection;
private static function &getConnection() {
if (!self::$connection) {
self::$connection = new DB_Connection();
}
return self::$connection;
}
public static function &query($sql) {
$dbh = self::getConnection();
return $dbh->query($sql);
}
}
class Item {
public static function &getList() {
return DB::query("SELECT * FROM items");
}
}
/**
* OPTION 2
*
* Pros: Don't have to wrap every DB_Connection function like in Option 1
* Cons: Every function in the model is responsible for checking the connection
*/
class DB {
protected static $connection = null;
public function connect() {
self::$connection = new DB_Connection();
}
}
class Item extends DB {
public static function &getList() {
if (!self::$connection) $this->connect();
return self::$connection->query("SELECT * FROM items");
}
}
/**
* OPTION 3
*
* Use magic methods
*
* Pros: Simple model code AND don't have to reimplement the DB_Connection interface
* Cons: __callStatic requires PHP 5.3.0 and its args can't be passed-by-reference.
*/
class DB {
private static $connection = null;
public static function &getConnection() {
if (!self::$connection) {
self::$connection = new DB_Connection();
}
return self::$connection;
}
public static function __callStatic($name, $args) {
if (in_array($name, get_class_methods('DB_Connection'))) {
return call_user_func_array(
array(self::getConnection(), $name), $args);
}
}
}