How to properly set up a PDO connection
I would suggest not using $_SESSION
to access your DB connection globally.
You can do one of a few things (in order of worst to best practices):
- Access
$dbh
usingglobal $dbh
inside of your functions and classes Use a singleton registry, and access that globally, like so:
$registry = MyRegistry::getInstance(); $dbh = $registry->getDbh();
Inject the database handler into the classes that need it, like so:
class MyClass { public function __construct($dbh) { /* ... */ } }
I would highly recommend the last one. It is known as dependency injection (DI), inversion of control (IoC), or simply the Hollywood principle (Don't call us, we'll call you).
However, it is a little more advanced and requires more "wiring" without a framework. So, if dependency injection is too complicated for you, use a singleton registry instead of a bunch of global variables.
I recently came to a similar answer/question on my own. This is what I did, in case anyone is interested:
<?php
namespace Library;
// Wrapper for \PDO. It only creates the rather expensive instance when needed.
// Use it exactly as you'd use the normal PDO object, except for the creation.
// In that case simply do "new \Library\PDO($args);" with the normal args
class PDO
{
// The actual instance of PDO
private $db;
public function __construct() {
$this->args = func_get_args();
}
public function __call($method, $args)
{
if (empty($this->db))
{
$Ref = new \ReflectionClass('\PDO');
$this->db = $Ref->newInstanceArgs($this->args);
}
return call_user_func_array(array($this->db, $method), $args);
}
}
To call it you only need to modify this line:
$DB = new \Library\PDO(/* normal arguments */);
And the type-hinting if you are using it to (\Library\PDO $DB).
It's really similar to both the accepted answer and yours; however it has a notably advantage. Consider this code:
$DB = new \Library\PDO( /* args */ );
$STH = $DB->prepare("SELECT * FROM users WHERE user = ?");
$STH->execute(array(25));
$User = $STH->fetch();
While it might look like normal PDO (it changes by that \Library\
only), it actually doesn't initialize the object until you call the first method, whichever it is. That makes it more optimized, since the PDO object creation is slightly expensive. It's a transparent class, or what it's called a Ghost, a form of Lazy Loading. You can treat the $DB as a normal PDO instance, passing it around, doing the same operations, etc.
The goal
As I see it, your aim in this case is twofold:
- create and maintain a single/reusable connection per database
- make sure that the connection has been set up properly
Solution
I would recommend to use both anonymous function and factory pattern for dealing with PDO connection. The use of it would looks like this :
$provider = function()
{
$instance = new PDO('mysql:......;charset=utf8', 'username', 'password');
$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $instance;
};
$factory = new StructureFactory( $provider );
Then in a different file or lower in the same file:
$something = $factory->create('Something');
$foobar = $factory->create('Foobar');
The factory itself should look something like this:
class StructureFactory
{
protected $provider = null;
protected $connection = null;
public function __construct( callable $provider )
{
$this->provider = $provider;
}
public function create( $name)
{
if ( $this->connection === null )
{
$this->connection = call_user_func( $this->provider );
}
return new $name( $this->connection );
}
}
This way would let you have a centralized structure, which makes sure that connection is created only when required. It also would make the process of unit-testing and maintenance much easier.
The provider in this case would be found somewhere at the bootstrap stage. This approach would also give a clear location where to define the configuration, that you use for connecting to the DB.
Keep in mind that this is an extremely simplified example. You also might benefit from watching two following videos:
- Global State and Singletons
- Don't Look For Things!
Also, I would strongly recommend reading a proper tutorial about use of PDO (there are a log of bad tutorial online).