I've spent the last several hours trying to find an answer to the "best", most logical, etc way to write a php database class to simultaneously connect to one postgresql db and one mysql db. Also, I'd like to adopt a Dependency Injection design but am new to that whole concept.
So far I've come up with...
class Database {
public function PgSqlConnect() {
/* Connect to database */
$host = 'localhost';
$dbname = '---';
$user = '---';
$pass = '---';
$timeout = 5; /* seconds */
try {
$pgsql_dbh = new PDO("pgsql:host=$host; dbname=$dbname", $user, $pass);
$pgsql_dbh->setAttribute( PDO::ATTR_TIMEOUT, $timeout );
$pgsql_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $pgsql_dbh;
} catch( PDOException $e ) {
echo 'Unable to connect to database: ' . $e->getMessage();
}
}
public function MySqlConnect() {
/* Connect to database */
$host = 'localhost';
$dbname = '---';
$user = '---';
$pass = '---';
$timeout = 5; /* seconds */
try {
$mysql_dbh = new PDO("mysql:host=$host; dbname=$dbname", $user, $pass);
$mysql_dbh->setAttribute( PDO::ATTR_TIMEOUT, $timeout );
$mysql_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
return $mysql_dbh;
} catch( PDOException $e ) {
echo 'Unable to connect to database: ' . $e->getMessage();
}
}
}
Obviously the duplicated code violates the DRY approach. I know and have seen many examples of multiple db connections, but most deal with same driver and don't provide DI capability.
I should also add that I've considered placing the connection details into the Database class constructor as...
$driver = 'mysql';
...
$mysqldb = new Database($driver,$un,$pw,...);
$driver = 'pgsql';
...
$pgsqldb = new Database($driver,$un,$pw,...);
but I don't know if that is really a good idea nor how well it would work with DI.
Many thanks!
You should create an interface first for all the DB operations.
interface IDatabase
{
function connect();
function query();
...
}
Then have different driver classes implementing this interface
class MySQLDB implements IDatabase
{
}
class PGSQLDB implements IDatabase
{
}
This way you can easily use dependency injection.
class Test
{
private $db;
function __construct(IDatabase $db)
{
$this->db = $db;
}
}
You can call it as:
$mysqldb = new MySQLDB();
$test = new Test($mysqldb);
or
$pgsqldb = new PGSQLDB();
$test = new Test($pgsqldb);
To avoid duplicated code you can extend an abstract class
abstract class AbstractDb {
public function connect() {
// common code to avoid duplication
echo 'connected!';
}
abstract public function escapeField();
abstract public function escapeValue();
}
class MySQL extends AbstractDb {
public function escapeField() {
// Db-specific method
}
public function escapeValue() {
// Db-specific method
}
}
$db = new MySQL;
$db->connect();
Or use composition, and let the Db class use a different driver for db-specific methods
interface IDriver {
public function escapeField();
public function escapeValue();
}
class MySQLDriver implements IDriver {
public function escapeField() {
// Db-specific method
}
public function escapeValue() {
// Db-specific method
}
}
class Db {
public function __construct($driver) {
$this->driver = $driver;
}
public function connect() {
// common code here ? idk, it's just an example
echo 'connect!';
}
// this method is db-specific, so we call the driver
public function escapeField($field) {
return $this->driver->escapeField($field);
}
public function escapeValue() {
// same here
}
}
$db = new Db(new MySQLDriver);
$db->connect();
In php 5.4 there will be traits, so there will be more approaches to avoid code duplication.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With