PHP - How do I replace this Singleton? - Custom DBAL - php

I am rather new to the concepts of design patterns and I'm thinking of using Dependency Injection and Polymorphism (as each are applicable) -- but I have many Singletons and while most of them can easily be changed, my DBAL cannot.
The reason why is the DBAL creates a connection to the Database -- sets up it's own PDO object. If I passed new DBALs to every class that needs it (quite a few) I would get multiple, unnecessary connections to the database.
The class is something like this
class DB {
/**
* Hold the PDO object
* #var PDO
*/
private $_db;
/**
* Hold the last error messages
* #var string
*/
private $_error_message = NULL;
/**
* Hold the last error code
* #var int
*/
private $_error_code = NULL;
/**
* Connects to the database server and selects a database
*
* #param string $user MySQL database user
* #param string $password MySQL database password
* #param string $name MySQL database name
* #param string $host MySQL database host
* #return bool
*/
public function connect( $user, $password, $name, $host ) {
// Connect
try {
$this->_db = new PDO( "mysql:host=$host;dbname=$name", $user, $password );
} catch ( PDOException $e ) {
$this->_error_message = $e->getMessage();
$this->_error_code = $e->getCode();
return false;
}
return true;
}
// ...
}
?>
There will be many classes that inherit this class -- what is the best way to handle this? (I am new to design patterns)

An alternative method is to use a registry:
$db = new DB($host, $user, $pass);
Config::set('db', $db);
// Inside other classes
Config::get($this, 'db');
// Passes $this so the config can override the DB for different classes
Problem here is you end up with a Config singleton.
To truly do DI, you basicly need to pass object around to every other object.
$db = new DB($host, $user, $pass);
$user = new User($db);
// Or with a DI container
$c = new Pimple();
$c['db'] = function() {
return new DB($host, $user, $pass);
};
But ask yourself why you don't want to use a singleton.
If it looks like a singleton, smells like a singleton, and you use it like a singleton, then a singleton pattern is probably the best fit for the job.
http://pimple.sensiolabs.org/

add to the class:
private function __construct($user, $password, $name, $host ){
connect( $user, $password, $name, $host );
}
public static function getInstance(){
if(self::$_db == NULL) self::$_db = new DB;
return self::$_db;
}
and change the following:
// change $_db to be static!
private static $_db = NULL;

Related

Retrieving a connection inside a page: PDO and PHP class

I'm new to classes and PDO as well. I'm trying to write a class with separate functions for connecting to the db and closing the connection so that, in a page, I can:
Open the connection with the $db->connOpen
Perform all the queries I need inside the page
Close the connection at the end of the script with $db->connClose
class database
{
private $host = '';
private $db_name = '';
private $charset = '';
private $username = '';
private $password = '';
public function setHost($host) {
$this->host = $host;
}
public function setDbName($db_name) {
$this->db_name = $db_name;
}
public function setUser($username, $password) {
$this->username = $username;
$this->password = $password;
}
public function connOpen() {
try {
$dsn = "mysql:host=$this->host;dbname=$this->db_name;charset=$this->charset";
$db = new PDO($dsn, $this->username, $this->password, array(PDO::ATTR_PERSISTENT => true));
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
public function connClose() {
$db = null;
}
}
I guess the problem is regarding more the classes syntax than the PDO, since to fire a query like the one below into the page I would need to instantiate again the class PDO, doubling the connection to the db.
$stmt = $dbo->prepare('SELECT * FROM products WHERE id=:id');
$stmt->execute(array(':id' => $id));
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);
My questions are:
How can achieve what I want using a class like the one above?
Is it correct, in this case, using a persistent connection?
Thanks
For some reason, most people who wants to learn OOP starts with a database wrapper that implements singleton and interferes with error handling.
My tip is that you treat the database connection as any other variable:
class Post {
function getByUserId(PDO $connection, $user_id) {
}
}
$database = new PDO(...);
$post->getByUserId($database, 123);
This is called dependency injection.
And don't waste time and energy writing code to avoid useful features, such as:
Centralised error handling
Being able to connect to more than one database
Only care about writing a database wrapper when you really have real features to add on top of PDO. I can think of:
Convert dates to DateTime objects automatically
Pass all queries to a logger
Throw custom exceptions on interesting events, such as duplicate index violation
... and even then be extremely careful to not make PDO worse ;-)
I am using this with one singlton class which give me db ojbect and then I am using that object to query in other classes;
<?php
class db{
/*** Declare instance ***/
private static $instance = NULL;
/**
*
* the constructor is set to private so
* so nobody can create a new instance using new
*
*/
private function __construct() {
/*** maybe set the db name here later ***/
}
/**
*
* Return DB instance or create intitial connection
*
* #return object (PDO)
*
* #access public
*
*/
public static function getInstance() {
if (!self::$instance)
{
self::$instance = new \PDO("mysql:host=".databaseHost.";dbname=".databaseName."", databaseUserName,databasePassword);;
self::$instance-> setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
self::$instance-> setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
}
return self::$instance;
}
/**
*
* Like the constructor, we make __clone private
* so nobody can clone the instance
*
*/
private function __clone(){
}
} /*** end of class ***/
?>
class where i am querying using db object
<?php
class posts {
public function getPostOfUserId($userId,$offset=0,$limit=NULL){
$helperString=" ";
if(!empty($limit))
$helperString=" LIMIT $offset, $limit ";
$executor= db::getInstance()->prepare("SELECT posts.*,users.facebook_id, users.first_name as post_by FROM posts JOIN tagged_friends ON posts.id = tagged_friends.post_id JOIN users ON posts.user_id = users.id WHERE tagged_friends.user_id = :user_id ORDER BY posts.id DESC ".$helperString, array(\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY));
$executor->execute(array(':user_id'=>$userId));
$posts=$executor->fetchAll(\PDO::FETCH_ASSOC);
if(!empty($posts))
return $posts;
else
return ;
}
}

Passing DB access class with REQUIRE or dependency injection?

Similar questions have been asked but I believe they do not cover my case.
I experimented with a few ways to pass db class to other classes for access and found that the below works well.
My question is: is there anything wrong with that approach and whether Dependency Injection will be a better solution?
class Database{
private $db_host = "localhost";
private $db_user = "root";
private $db_password = "";
private $db_name = "dbName";
private $pdo;
public $instance;
function __construct() {
try{
//create a PDO connection and assign it to some handler
$this->pdo = new PDO('mysql:host='. $this->db_host.';dbname='. $this->db_name, $this->db_user, $this->db_password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
// echo "connected";
} catch (PDOException $e) {
exit("Error connecting to database". $e->getMessage());
}
}
public function getPDO(){
return $this->pdo;
}
}
class OtherClass{
require_once 'Database.php';
private $db_instance;
private $dbh;
function __construct() {
$this->db_instance = new Database();
$this->dbh = $this->db_instance->getPDO();
}
}
How about a simple class from which you can create and destroy a connection to the database if its not needed. Lets refractor your code abit.
First create a classname that can be identified easily, something like
class pdo_mysql{
Its a pdo class, but based on mysql, next declare some variables, (The explanation in the comments)
/*
* Description - The name of the database
*/
private $dbname;
/*
* Description - The database username
*/
private $dbuser;
/*
* Description - The database password
*/
private $dbpass;
/*
* Description - The database Host
*/
private $dbhost;
/*
* Description - The database driver
* #Parameters - null
* To do -
* Notes:
*/
private $dbdriver;
/*
* Description - Stores the connection to the database
*/
private $con;
Then lets define the constructor for our class:
/*
* Description - This is the default method that is called when this class is instantiated.
* #Parameters - dbhost|dbdriver|dbname|dbusername|dbpassword
*/
function __construct($dbhost, $dbdriver, $dbname, $dbuser, $dbpass){
$this->dbhost = $dbhost;
$this->dbdriver = $dbdriver;
$this->dbname = $dbname;
$this->dbuser = $dbuser;
$this->dbpass = $dbpass;
}
Note that when the class is instantiated, most class variables are set.
Then our connection function:
/*
* Description - Creates a connection to the database
* Notes: - Returns true on success || string with an error msg on failure
*/
private function _connect(){
try {
$this->con = new PDO(''.$this->dbdriver.':host='.$this->dbhost.';dbname='.$this->dbname.'', $this->dbuser, $this->dbpass);
$this->con->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$this->con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return true;
} catch (PDOException $e){
return $e->getMessage();
}
}
And finally a function to disconnect our connectio to the database:
/*
* Description - Disconnects database connection
*/
private function _disconnect(){$this->con = null;return true;}
And a finally a function to query the database:
/*
* Description - Retrieves information from the database
*/
function _loadResult($data){}
This class will use data that is pre populated, so lets create for it a function to initialize it: (this should be in a different file/class)
/*
* Description - Get the config options from a file and initiate the database object
* Notes: - Returns a new object of the database connection class on success | false on fail
the config file must contain the following values dbhost|dbengine|dbname|dbusername|dbpassword
*/
static public function getDbo(){
if(!is_readable(/*path to your config file*/)){// lets check that the config file exists and is readable
return 'ERROR - The config file is missing or its unreadable!';
}
$config = parse_ini_file(/*path to your config file*/);
if($config === false){//parse the config file and return an error incase the purse fails
return 'ERROR - Could not parse the config file!';
}
//the following values are populated by the ones parsed from the config file
$dbhost = $config['dbhost'];
$dbclassprefix = $config['dbclassprefix'];
$dbdriver = $config['dbdriver'];
$dbname = $config['dbname'];
$dbuser = $config['dbuser'];
$dbpass = $config['dbpass'];
static $dbobject = null;//create the database object if all went well
if(null === $dbobject){$dbclass = $dbclassprefix.$dbdriver;$dbobject = new $dbclass($dbhost, $dbdriver, $dbname, $dbuser, $dbpass);}
return $dbobject;//return the database object
}
A case usage of the above code:
$db = self::getDbo();//create the database object
if(is_string($db)){//if the return value is a string, then thats an error
//return an error
}
$res = $db->_loadResult($data);//call a function from the database class
This is just a shaddy example from my head to give you some rough ideas, but its fully guaranteed to work if coded correctly, with the above classes and functions, you can change the engine to either PDO_mysqli or another another by changing the value in your config file. Hope you get the idea

How do I make sure I am not recreating multiple DB connections in PHP class?

I am not real good at this yet and I have tried to figure it out but can't seem to do so.
I am trying to write a PHP class which reuses its database connection and doesn't make a new one every time it needs it. How do I make sure I am not recreating a new connection every time?
Please consider the code below and let me know if I am creating several connections or reusing the same one in the PHP file.
Thanks
PHP File
require_once(class.myclass.php);
$object = new myclass;
[...modify $object properties...]
if ($object->save_to_db()) {
echo "OK \n";
}
else {
echo "FAIL :" . $object->get_err();
}
[...modify $object properties...]
if ($object->save_to_db()) {
echo "OK \n";
}
else {
echo "FAIL :" . $object->get_err();
}
unset($object);
Class file
class myclass {
private $id;
private $db; // Database Connection
private $err; // Error
public function save_to_db() {
$db = $this->get_db();
$query = "...";
if(!$db->execute($query)) {
$this->err = $db->get_err();
$save_to_db = false;
}
else {
$save_to_db = true;
}
unset($db);
return $save_to_db;
}
private function get_db() {
if (!isset($this->db)) {
$this->db = new db;
}
return $this->db;
}
public function get_err() {
return $this->err;
}
function __destruct() {
if (isset($this->db)) {
unset($this->db);
}
}
}
A really good way to create a database handler is to use a static class method which returns itself. Called a Singleton pattern.
class DB {
/**
* Points to the instance of this class.
* #var object
*/
private static $instance = null;
/**
* Points to the database connection
* #var object
*/
private $db;
/**
* Initiates a new instance of self if one isn't set and opens a db connection
* #return object an object of self
*/
public static function getInstance() {
if(self::$instance == null) {
self::$instance = new self;
$this->db = new PDO();
}
return self::$instance;
}
/**
* Runs a query on the database
* #param string $query the query to run on the db
* #return array the result set
*/
public function query($query) {
// Query..
$stmt = $this->db->prepare("SELECT * FROM table");
$stmt->execute();
return $stmt->fetchAll();
}
}
And the simple usage would be:
$result = DB::getInstance()->query("SELECT * FROM table");
var_dump($result); // Outputs array of results.
This will only open one connection the first time you invoke DB::getInstance(). This way, you don't have to initiate the class and it supports chaining. This method is used by the Laravel framework aswell.
There are various ways of doing this, as lxg stated, the singleton method is one way of doing it, but you can also assign the class the connection which you open at the start of the scripts runtime.
class NeedDB {
/**
* Points to the DB connection
* #var object
*/
private $db;
/**
* Class constructor
* #param object $db The DB connection object
*/
public function __construct($db) {
$this->db = $db;
}
/**
* Runs a query on the database
* #param string $query the query
* #return array the result set
*/
public function query($query) {
$stmt = $this->db->prepare($query);
$stmt->execute();
return $stmt->fetchAll();
}
}
$db = new PDO();
$class = new NeedDB($db);
$result = $class->query("SELECT * FROM table");
var_dump($result);
There are several approaches to this. Generally, when creating a “real-world” application, you would use a decent framework which provides the database connection and common DB features as a dependency/service.
But while you're playing, these are the most common for a simple use case:
A) The Singleton design pattern. (Using singletons is discouraged these days in favour of dependency injection, but for the sake of playing/learning, it's acceptable to use it.)
B) Assign the DB connection to a global variable (i.e. outside the context of any function) and import it, when you need it, with the global keyword. This would look something like this:
$db = createMyConnection();
function iNeedTheDbConnection()
{
global $db;
// here goes the code that uses the connection
}
This is actually even worse than the singleton, but it works, and is still widely used (e.g. in WordPress).

PHP OOP database connect

I have just started learning the concept of Object oriented programming and I've written this class with functions.
It works fine, but I'm interested in knowing if I have done this correctly...
Here is my code:
class Database{
const DB_HOSTNAME = 'localhost';
const DB_USERNAME = 'root';
const DB_PASSWORD = 'password';
const DB_NAME = 'shop';
protected $_db_connect;
protected $_sql;
protected $_result;
protected $_row;
function db_connect(){
$this->_db_connect = mysql_connect(self::DB_HOSTNAME,self::DB_USERNAME,self::DB_PASSWORD) or die(mysql_error());
}
function slect_db(){
mysql_select_db(self::DB_NAME) or die(mysql_error());
}
function sql(){
$this->_sql = 'SELECT * FROM users';
}
function query(){
$this->_result = mysql_query($this->_sql);
}
function fetch_array(){
while($this->_row = mysql_fetch_array($this->_result)){
$username = $this->_row['user_USERNAME'];
echo "<ul>";
echo "<li>".$username."</li>";
echo "</ul>";
}
}
function db_close(){
mysql_close($this->_db_connect);
}
}
$database = new Database();
$database->db_connect();
$database->slect_db();
$database->sql();
$database->query();
$database->fetch_array();
$database->db_close();
Please use PDO or MySQLi as it's more secure and mysql_* functions are deprecated as stated above, I've provided some generic code using PDO to help you with that new venture. As stated in the comments, you really shouldn't be echoing out the data if you're looking for an object oriented design, what you should be doing is after you do the query, return the rows that you fetched and from there use something such as a foreach loop to then display your data. Doing your database class this way will also make sure that multiple database connections aren't open at once! Note, this code is just for you to reference, and should be tested before use in production or anything live.
config.php:
<?php
//Enter your database connection details here.
$host = 'localhost'; //HOST NAME.
$db_name = 'databasename'; //Database Name
$db_username = 'root'; //Database Username
$db_password = ''; //Database Password
try
{
$pdo = new PDO('mysql:host='. $host .';dbname='.$db_name, $db_username, $db_password);
}
catch (PDOException $e)
{
exit('Error Connecting To DataBase');
}
?>
database.class.php:
<?php
class database
{
function __construct($pdo)
{
$this->pdo = $pdo;
}
function getData()
{
$query = $this->pdo->prepare('SELECT * FROM database');
$query->execute();
return $query->fetchAll();
}
}
?>
index.php:
<?php
require_once 'config.php';
require_once 'database.class.php';
$db = new database($pdo);
$rows = $db->getData();
?>
It is possible to improve the way you connect to databases using autoloading and dependency injection containers. Here is a way of using Auryn to connect to your database while being sure there is only one connection opened and not having to manually require files throughout your application.
I will cover only PDO and Auryn here. There are other dependency injection containers and notably the mysqli extension to connect to database, but the content should help you using another container if you wish to do so.
The database class
Having a database class is superfluous. The \PDO class is already providing all necessary methods to query the database. Having a database class makes you repeat the functions it provides and limits your actions (or makes you create many functions) when you want to for example use multiple different fetch styles depending on your needs in a specific method.
Dependency Injection
If you haven't already, have a read on dependency injection. The point is that when a class needs to access the database, it should not have to bother constructing the \PDO object, it should be constructed with it:
class Mapper {
private $pdo;
public function __construct(\PDO $pdo) {
$this->pdo = $pdo;
}
public function createFromId($id) {
$stmt = $this->pdo->prepare("SELECT name FROM foo WHERE id=:id");
$stmt->execute([
":id" => $id,
]);
return $stmt->fetchObject();
}
}
Notice that I directly pass the \PDO object, not a wrapper class. That way, I always have access to all of its capabilities, not only a subset of user-defined functions.
Dependency Injection Container
A dependency injection container helps build your classes, giving them the objects they need, and giving you great flexibility on how to actually build those objects. Here I'll only focus on configuring and sharing a \PDO object through the use of Auryn.
I assume you have installed the required Auryn class, the easier way is using composer. This is out of the scope of this answer, there are multiple resources on how to use it.
Create the injector
$injector = new \Auryn\Injector();
Define the \PDO class parameters
$injector->define("PDO", [
":dsn" => "mysql:host=localhost;charset=utf8;dbname=dbname",
":username" => "user",
":passwd" => "passwd",
":options" => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
],
]);
You can either write the configuration parameters directly here, or get them from a config file. I like having a config.ini file and using parse_ini_file() to get my configuration options, as I can easily switch databases by editing a config file.
Share the \PDO object
$injector->share("PDO");
This part is really important. This lines makes the injector give the same \PDO object every time it is tasked with constructing a class that needs a connection. Note that the order of the lines is not important, you can share the class before defining it, only make sure to create you database needing classes after writing both those lines.
Create your objects
$mapper = $injector->make("Mapper");
That's it. The injector will create your mapper object, creating the \PDO object if it haven't already been, passing the existing instance if it has.
Autoloading
Assuming you have used composer, you can make use of its great autoloader. Otherwise you can also roll you own autoloader.
The point here is to stop having require() everywhere in your code, especially if you have complex class hierarchies, which you should have in a single responsibility compliant class system.
Wrapping up
With this set up, you now can use the \PDO object in your classes while being assured there will only be one instance per request, without the need to require files everywhere, and without using a singleton anti-pattern.
$database = new Connection();
class Connection
{
function __construct()
{
switch($_SERVER['DOCUMENT_ROOT'])
{
case 'path':
$this->host = 'hostname';
$this->user = 'username';
$this->passwd = 'password';
$this->database = 'dbname';
break;
default :
$this->host = 'localhost';
$this->user = 'root';
$this->passwd = 'root';
$this->database = 'dbname';
break;
}
$this->clink = #mysql_connect($this->host,$this->user,$this->passwd);
#mysql_select_db($this->database,$this->clink);
}
}
$objConn = new mysqlconnect();
$Conn = $objConn->setobjConnect("localhost","root","P#ssw0rd");
class Database{
var $last_query; //Saved result of the last query made
var $last_result; //Results of the last query made
var $func_call; //A textual description of the last query/get_row/get_var call
var $link; //database link
var $lastquery; //last query
var $result; //query result
// Connect to MySQL database
function database() {
$this->link=mysql_connect(DB_HOST, DB_USER, DB_PASS) or die('Server connexion not possible.');
//Set All Charsets to UTF8
mysql_query("SET character_set_results=utf8 , character_set_client=utf8 , character_set_connection=utf8 , character_set_database=utf8 , character_set_server=utf8");
mysql_select_db(DB_NAME) or die('Database connection not possible.');
}
/** Query the database.
* #param $query The query.
* #return The result of the query into $lastquery, to use with fetchNextObject().
*/
function query( $query ){
$this->lastquery=$query;
$this->result=#mysql_query( $query, $this->link );
return $this->result;
}
/** Do the same as query() but do not return nor store result.
* Should be used for INSERT, UPDATE, DELETE...
* #param $query The query.
* #param $debug If true, it output the query and the resulting table.
*/
function execute($query)
{
#mysql_query($query);
}
/** Convenient method for mysql_fetch_object().
* #param $result The ressource returned by query().
* #return An ARRAY representing a data row.
*/
function fetchArray($result){
if ($result == NULL)
$result = $this->result;
if ($result == NULL || mysql_num_rows($result) < 1)
return NULL;
else
return mysql_fetch_assoc($result);
}
/** Close the connecion with the database server.
* It's usually unneeded since PHP do it automatically at script end.
*/
function close()
{
mysql_close($this->link);
}
/** Get the number of rows of a query.
* #param $result The ressource returned by query(). If NULL, the last result returned by query() will be used.
* #return The number of rows of the query (0 or more).
*/
function numRows($result = NULL)
{
if ($result == NULL)
return #mysql_num_rows($this->result);
else
return mysql_num_rows($result);
}
}
![<?php
class mysqlconnect{
private $server=null;private $user=null;private $password=null;private $objConnect=null;
function setobjConnect($s,$u,$p){
$this->server = $s;
$this->user = $u;
$this->password = $p;
return $this->objConnect = mysql_connect($this->server,$this->user,$this->password);
}
}
$objConn = new mysqlconnect();
$Conn = $objConn->setobjConnect("localhost","root","P#ssw0rd");
if($Conn)
{
echo "Database Connect";
}
else
{
echo "Database Connect Failed.";
}
mysql_close($Conn);
?>]
1

PHP - a DB abstraction layer use static class vs singleton object?

I don't want to create a discussion about singleton better than static or better than global, etc. I read dozens of questions about similar subjects on SO, but I couldn't come up with an answer to this SPECIFIC question, so I hope someone could now illuminate me by answering this question with one (or more) real simple EXAMPLES, and not just theoretical discussions.
In my app I have the typical DB class to abstract the DB layer and to perform tasks on DB without having to write everywhere in code mysql_connect / mysql_select_db / mysql...
I could write the class either as a STATIC CLASS:
class DB
{
private static $connection = FALSE; //connection to be opened
//DB connection values
private static $server = NULL; private static $usr = NULL; private static $psw = NULL; private static $name = NULL;
public static function init($db_server, $db_usr, $db_psw, $db_name)
{
//simply stores connections values, without opening connection
}
public static function query($query_string)
{
//performs query over alerady opened connection, if not open, it opens connection 1st
}
...
}
OR as a SINGLETON:
class DBSingleton
{
private $inst = NULL;
private $connection = FALSE; //connection to be opened
//DB connection values
private $server = NULL; private $usr = NULL; private $psw = NULL; private $name = NULL;
public static function getInstance($db_server, $db_usr, $db_psw, $db_name)
{
//simply stores connections values, without opening connection
if($inst === NULL)
$this->inst = new DBSingleton();
return $this->inst;
}
private __construct()...
public function query($query_string)
{
//performs query over already opened connection, if connection is not open, it opens connection 1st
}
...
}
Then after in my app if I want to query the DB i could do
//Performing query using static DB object
DB:init(HOST, USR, PSW, DB_NAME);
DB::query("SELECT...");
//Performing query using DB singleton
$temp = DBSingleton::getInstance(HOST, USR, PSW, DB_NAME);
$temp->query("SELECT...");
To me Singleton has got the only advantage to avoid declaring as static each method of the class. I'm sure some of you could give me an EXAMPLE of real advantage of singleton in this specific case. Thanks in advance.
What is wrong with the following (simplified) example:
class Database
{
protected $_connection;
protected $_config;
public function __construct( array $config ) // or other means of passing config vars
{
$this->_config = $config;
}
public function query( $query )
{
// use lazy loading getter
return $this->_getConnection()->query( $query );
}
protected function _getConnection()
{
// lazy load connection
if( $this->_connection === null )
{
$dsn = /* create valid dsn string from $this->_config */;
try
{
$this->_connection = new PDO( $dsn, $this->_config[ 'username' ], $this->_config[ 'password' ] );
}
catch( PDOException $e )
{
/* handle failed connecting */
}
}
return $this->_connection;
}
}
$db1 = new Database( array(
'driver' => 'mysql',
'host' => 'localhost',
'dbname' => 'test',
'username' => 'test_root',
'password' => '**********'
) );
$db2 = new Database( array(
'driver' => 'pgsql',
'host' => '213.222.1.43',
'dbname' => 'otherdb',
'username' => 'otherdb_root',
'password' => '**********'
) );
$someModel = new SomeModel( $db1 );
$someOtherModel = new SomeOtherModel( $db2 );
$yetAnotherModel = new YetAnotherModel( $db2 );
This demonstrates how you can make use of lazy loading connections, and still have flexibility to use different database connections.
The database instances will only connect to their individual connection when an object that consumes one of the instances (in this case one of the models) decides to call a method of the instance.
In my most recent project, I actually went against the "good" design principles by making the database class entirely static. The reason behind this is that I used a lot of caching on PHP objects. Originally I had the database passed in through the constructor of each object as a dependency injection, however I wanted to make sure that the database didn't have to connect unless absolutely necessary. Thus, using a database as a member variable of that object would not have been practical because if you unserialized an object from the cache, you wouldn't want to connect to the database unless you actually performed an operation on it.
So in the end I had only two (public) static functions, Database::fetch() and Database::execute() which would check whether or not it had already connected, and if not, it would connect and perform the query. This way I wouldn't have to worry about deserialization and would connect as seldom as possible. It technically makes unit testing impossible though.
You don't always have to follow every single good practice. But I would still recommend against doing what I did since some would consider it premature optimization.
My advice: STOP using Singleton and static all together.
Why? Because you will insert dependencies that will render your code unusable in other projects, and will not allow to unit test it. Also forget about loose coupling if using singleton.
The alternatives? Dependency Injection.
http://www.potstuck.com/2009/01/08/php-dependency-injection
Making DB library static is certainly shorter and quicker, than doing:
$db = DBSingleton::blabla(); // everytime I need ya
But also, since it is global, tempting to use everywhere.
So, choose other methods if you want clean code... and choose static if you need quick code ;-)
/* Data base*/
class Database
{
/* Database field definition */
private static $_instance; /instance
private $_connection;
private $DB_USER = "database_user_name_here";
private $DB_PASS = "your_password_here";
private $DB_NAME = "your_database_name_here";
private $DB_SERVER = "localhost";
/* Initiate the database connection */
private function __construct()
{
$this->_connection = new mysqli($this->DB_SERVER ,
$this->DB_USER ,
$this->DB_PASS ,
$this->DB_NAME);
/* Test if connection succeeded */
if (mysqli_connect_errno()) {
die("Database connection failed: " .
mysqli_connect_error() .
" (" . mysqli_connect_errno() . ")"
);
}
}
/**
* Instance of the database
* #return Database
*
*/
public static function Instance()
{
if (!self::$_instance) { // If no instance then make one
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Void duplicate connection
*/
private function __clone() { }
/* Return a connection */
public function getConnection()
{
return $this->_connection;
}
}
/** This is how you would use it in a different class.
#var TYPE_NAME $connection */
$db = Database::Instance();
$connection = $db->getConnection();

Categories