Problem
I have that $db, that I will use again and again to connect to the database. How do I put this in a central location so if I change my db I will not have to rewrite a bunch of lines of code? Everything I’ve tried so far just gives me an error concerning variable scope, the variable is not declared in my functions, so I am forced to simply connect and use the $db object everytime I need to access the database.
TLDR: How do I create the $db object once, and then use it again and again. Just looking for a general idea here.
function input_registration ($email, $password) {
$email_clean = htmlspecialchars($email);
$password_clean = htmlspecialchars($password);
$hash = md5($password_clean);
$db = new PDO("mysql:host=localhost;dbname=users", "root", "");
try {
$statement = $db->prepare("INSERT into userinfo(email, hash) VALUES (:email, :hash)");
$array_parameters = array(
'email' => $email_clean,
'hash' => $hash
);
$statement->execute($array_parameters);
}
catch (Exception $error) {
echo "Database error: ". $error->getMessage();
}
}
Solution
You can’t find the correct answer until your code is just a bunch simple PHP scripts. The ultimate solution would be is to use a dependency injection container and resolver where sou can say for example a PDO instance to keep in use until the request ends (in PHP this would be a singleton behavior).
If you can’t rewrite your whole system to have an object oriented design to have the ability to use a DI container then the only thing you could do is to create a class loader in your bootstrap section to load a factory.
A Factory is a simple class which can build object instances like a DatabaseFactory::CreateNewConnection would return a new PDO instance. You can create a static factory but that would be as flexible as the pig-iron. A recommend you to have a static DatabaseBuilder class there you can register a DatabaseFactory class instance as the default database factory and your factory can hold a database class instance until the request ends. Here is the skeleton:
<?php
class DatabaseFactoryBuilder {
private function __construct() {}
public static function SetFactory(IDatabaseFactory $factory) {
$this->_factory = $factory;
}
public static function GetFactory() {
return $this->_factory;
}
}
interface IDatabaseFactory {
function GetDatabase();
}
class DatabaseFactory implements IDatabaseFactory {
/* ... */
private $_db;
public function __construct($dbServer, $dbName, $dbUser, $dbPassword) {
/* ... */
}
public function GetDatabase() {
if ($this->_db == NULL) {
$this->_db = new PDO(/* ... */);
}
return $this->_db;
}
}
Ofcourse as you can se you have to create a decent way to set the connection properties for your database.
I’ll keep the procedural style, you use; otherwise I’d prefer object oriented code.
You need a function that creates the database connection on the first call and returns that connection on every call.
function getDbConnection()
{
static $db = null;
if (is_null($db)) {
$db = new PDO("mysql:host=localhost;dbname=users", "root", "");
}
return $db;
}
The static
keyword makes the variable keep its value after leaving the function.
Now the functions with database access only have to know the getDbConnection()
function, but no details about the connection.
function input_registration($email, $password)
{
try {
$db = getDbConnection();
$statement = $db->prepare("INSERT INTO userinfo(email, hash) VALUES (:email, :hash)");
$array_parameters = array(
'email' => $email,
'hash' => md5($password)
);
$statement->execute($array_parameters);
} catch (Exception $error) {
echo "Database error: ". $error->getMessage();
}
}
It is better design though, if any function that needs the database connection, gets it through its arguments.
function input_registration(PDO $db, $email, $password)
{
try {
$statement = $db->prepare("INSERT INTO userinfo(email, hash) VALUES (:email, :hash)");
$array_parameters = array(
'email' => $email,
'hash' => md5($password)
);
$statement->execute($array_parameters);
} catch (Exception $error) {
echo "Database error: ". $error->getMessage();
}
}