How do i make database object more efficient by reusing
I am confused on how to handle the logic of reusing the database object and configuration variables or constants that stands global for the application.
the way i have been doing till now is, i created a config.php
file in Config
directory and declare all the config
elements for example my typical config.php file would look like this.
#Start Session
session_start();
#Start Output Buffering
ob_start();
#Set Default TimeZone
date_default_timezone_set('Asia/Kolkata');
#Define Time Constant
define('DATE', date("d-F-Y/H:ia"));
#Define Paths
define('CLASSES',$_SERVER['DOCUMENT_ROOT'].'/resources/library/classes/');
define('MODELS',$_SERVER['DOCUMENT_ROOT'].'/resources/library/models/');
define('LOGS',$_SERVER['DOCUMENT_ROOT'].'/resources/logs/');
#Define Connection Constant
define('HOST','localhost');
define('USERNAME','username');
define('PASSWORD','password');
define('DATABASE','dbname');
try
{
#Connection String.
$dbh = new PDO('mysql:host='.HOST.';dbname='.DATABASE,USERNAME,PASSWORD);
#Set Error Mode to ERRMODE_EXCEPTION.
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
#Print Errors.
echo $e->getMessage();
#Log Errors into a file
file_put_contents(LOGS.'Connection-log.txt', DATE.PHP_EOL.$e->getMessage().PHP_EOL.PHP_EOL, FILE_APPEND);
}
#Autoload Classes.
function __autoload($class) {
require_once CLASSES.'class.'.strtolower($class).'.php';
}
and in index.php file i would include this file on开发者_JAVA技巧ce and re-use it in every object.
my index.php typically consist of controllers like this.
if(isset($_GET['users'])) {
require_once(MODELS.'users/users.php');
} else if(isset($_GET['categories'])) {
require_once(MODELS.'categories/categories.php');
} else if(isset($_GET['search'])) {
require_once(MODELS.'search/search.php');
}
and in Models i would instantiate the object i want and use it for example in users/users.php
i would instantiate it like this
$user = new User($dbh);
all is working fine but the problem is for each and every class i have to pass the database handle object through constructor and re-use it in the class which is kind of ugly for me. and this approach creates a problem for me if i want to use class which contains static methods and properties that holds the Application settings that is to be retrieved from database. my requirement is such that.
I want to create a static method using singleton pattern that will hold the database object that is to be used across the application without the need to pass the the $dbh
object each and everytime through constructor for each and every class. and i am very much confused on how should i deal with this.
thank you
I have a similar design pattern where I connect and store the connection in a global.
You do not need to pass the database variable to every class as it is a global.
You can use it anywhere like this:
$GLOBALS['dbh'];
To hide this I have actually created a function named get_db_connection()
which first checks if there is a valid connection in the $GLOBALS
array and then returns it. Also if there is no valid connection there, it creates a new connection stores it in the $GLOBALS and returns it.
It has the added benifit that I do need to instantiate the connection manually anywhere, it is automatically created on the first call to get_db_connection
and is available everywhere subsequently.
The get_db_connection
function looks something like this:
function get_db_connection(){
if(isset($GLOBALS['db_conn']) && get_class($GLOBALS['db_conn']) == 'PDO'){
return $GLOBALS['db_conn'];
}else{
$conn = new PDO(/* parameters */);
$GLOBALS['db_conn'] = &$conn;
return $conn;
}
}
defence in favour of global
I consider this to be an excusable usage of globals for following reasons:
- The variable $dbh is already a global as it is not inside a function or a class.
- You are not accessing the global directly anywhere in
your program, but only through a single function
get_db_connection
so the problem that anyone can change the value of the global is not here. - The only way around this is by using a Singleton, which may be unnecessary for such a simple problem.
Of these I consider the 2nd reason to be most concrete.
here is what i came up with finally.
class DB {
protected static $_dbh;
const HOST = 'localhost';
const DATABASE = 'dbname';
const USERNAME = 'usname';
const PASSWORD = 'passwo';
private function __construct() { }
public static function get_db_connection() {
if(!isset(self::$_dbh)) {
self::$_dbh = new PDO('mysql:host='.self::HOST.';dbname='.self::DATABASE,self::USERNAME,self::PASSWORD);
self::$_dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$_dbh;
}
}
Applying singleton pattern and with static method call i can easily access the database object without passing the database object through class constructor.
To call the database object within or outside the class scope all i have to do is call a single line of code.
DB::get_db_connection();
this sounds more feasible isn't it? :)
You could try something like this:
function cnn() {
static $pdo;
if(!isset($pdo)) {
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
$pdo->setAttribute(PDO::ATTR_TIMEOUT, 30);
$pdo->setAttribute(PDO::ATTR_PERSISTENT, true);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
return $pdo;
} else {
return $pdo;
}
}
After that, you can call any queries you want:
echo cnn()->query('SELECT firstname FROM user WHERE id=4;')->fetch(PDO::FETCH_COLUMN)
Second query (object is reused)
echo cnn()->query('SELECT title FROM news WHERE id=516;')->fetch(PDO::FETCH_COLUMN)
精彩评论