简体   繁体   中英

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 once 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.

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)

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? :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM