Making only one DB Connection with a Property
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
I can't stand it any longer. The app is small, but our database credentials
are already duplicated and hidden inside this one class. What if we added
a second table - like battle
- and a BattleLoader
class? At this rate,
we'd be copying and pasting the database password there too. Gross.
Isolate the PDO Creation in ShipLoader
Enough is enough. Let's fix this little by little. First, I don't want to
duplicate the new PDO
code twice in this class. To fix that, create a
private function getPDO()
- private because - at least so far - we only
want to call this from inside ShipLoader
. Copy the new PDO
line and
the one below it and put them here. Return $pdo
and let's even add some
nice PHPDoc:
// ... lines 1 - 2 | |
class ShipLoader | |
{ | |
// ... lines 5 - 48 | |
/** | |
* @return PDO | |
*/ | |
private function getPDO() | |
{ | |
$pdo = new PDO('mysql:host=localhost;dbname=oo_battle', 'root'); | |
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | |
return $pdo; | |
} | |
// ... lines 59 - 67 | |
} | |
// ... lines 69 - 70 |
You know what's next: use this above with: $pdo = $this->getPDO()
. Repeat
this in the other spot:
// ... lines 1 - 2 | |
class ShipLoader | |
{ | |
// ... lines 5 - 23 | |
*/ | |
public function findOneById($id) | |
{ | |
$statement = $this->getPDO()->prepare('SELECT * FROM ship WHERE id = :id'); | |
// ... lines 28 - 35 | |
} | |
// ... lines 37 - 59 | |
private function queryForShips() | |
{ | |
$statement = $this->getPDO()->prepare('SELECT * FROM ship'); | |
// ... lines 63 - 66 | |
} | |
} | |
// ... lines 69 - 70 |
Head back to the homepage! Ha! Nothing broken yet.
Prevent Multiple PDO Objects
Ok, a little bit better. Here's the next problem: what if a single page calls
findOneById()
multiple times? Well, getPDO()
would be called twice, two
PDO
objects would be created and this would mean that two database
connections would be made. Such waste! We only need one connection and we only
need one PDO
object.
How can we guarantee that only one PDO object is created?
By using a property! But in a way that we haven't seen yet. Up until now,
we've only put properties on our model classes - like Ship
- and that has
been to hold data about the object, like name
, weaponPower
, etc.
In service classes - any class whose main job is to do work instead of hold data - you use properties for two reasons: to hold options about how the class should behave. And to hold other tools - like a PDO object.
Create a private $pdo
property:
// ... lines 1 - 2 | |
class ShipLoader | |
{ | |
private $pdo; | |
// ... lines 6 - 71 | |
} | |
// ... lines 73 - 74 |
Now, we can use a little trick thanks to OO! Down in getPDO()
, add an if
statement to check if the pdo
property is equal to null
. Why of course
it is! So far, nothing is setting it, so it's always null. But now, if
it is null, move the new PDO()
code into this and then assign this to
the pdo
property. Finish by returning $this->pdo
:
// ... lines 1 - 2 | |
class ShipLoader | |
{ | |
private $pdo; | |
// ... lines 6 - 53 | |
private function getPDO() | |
{ | |
if ($this->pdo === null) { | |
$this->pdo = new PDO('mysql:host=localhost;dbname=oo_battle', 'root'); | |
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | |
} | |
return $this->pdo; | |
} | |
// ... lines 63 - 71 | |
} | |
// ... lines 73 - 74 |
The first time you call this, $this->pdo
is null so we create a new PDO
object and set the property. Then, if someone calls this during the same
request, the pdo
property will already be an object, so it'll skip creating
a second one and just return it. Boom!
This is the first time we've seen a service class - something that does work
for us - have a property. And in service classes, properties aren't about
holding data that describe something - like a Ship
- they're used to store
options about how the class should work or other useful objects that class
needs.
We shouldn't notice any difference - so refresh to try it. Yes! Think about it: thanks to objects, we were able to reduce the number of database connections being created by touching one file and not breaking anything.
Hi !
What do you mean by
?
This trick seams to be interesting only if the object lives during the whole session, not only during a simple request.