First of all, in case you don't know me that well, you need to know that I am
a big fan of unit testing. Although I like the idea of using a database abstraction layer, I have come to dislike PDO for several reasons. First of all it's behavior is not the same for every database driver that you use. This is not a fault of PDO itself so much as the authors of the database specific drivers that are not able to implement the entire feature set. Secondly, I am not sure I buy into this "You can just switch databases and all you have to do is change the config" argument. Any application that either has a DBA on the team or cares at all about performance will have tailored SQL to get the most out of the database - which as you know tends to be the main bottleneck in an application. The main reason that I dislike PDO is that it is such a pain to mock it while unit testing. For some reason it was deemed necessary to have PDO connect on construct rather than either having an explicit connect() method or a lazy connect when one is needed. Even though you can specify that you don't run the constructor when you mock PDO, you then run into internal trouble as some settings are not set up properly and you get errors. At work, I tend to just wrap PDO with my own Db class that proxies calls to the internal PDO instance so that I can mock my Db class and everything plays nicely.
For my own junk, I tend to always go with MySQL as my database so I don't really like the idea of adding a wrapper to a wrapper to a wrapper in order to talk to it. I use MySQLi as my db class, but I still wrap it so that I can do lazy connects. The reason for this is so that once my cache is warmed up, and the user has logged in, I
don't even connect to the database during a normal session. This helps tremendously as the connection to the database is the most expensive part of database interaction. If I do need to perform any write operations, they are performed by the Unit of Work, which doesn't kick in until the dipatchLoopShutdown. (I still have a few tweaks in regards to caching with my Unit of Work implementation before I show you how that works.) This also helps to ensure that if I do need to open a connection, it's for the shortest amount of time possible.
First, let's take a look at the MySQLi wrapper.
Pretty simple really as it essentially just wraps the MySQLi class. There are a couple of things to note however. First of all, if you are wondering what Naked_App::getWorkspace() is ... I'll explain that in my next post. Basically think of it like a registry that houses all of the tools I need to get work done in an application such as a database connection, a logger, and access control list etc. Another thing to note is that I am calling $this->connect() at the start of each method that requires that I am connected to the database. This is how I implement the lazy connect functionality. To make sure that I am not connecting needlessly I also log the fact that I connected and which methods forced me to connect. This can help me track down caching issues among other things. You can see what a typical log message looks like in FirePHP here:

I also wrap two other MySQLi classes for convenience. The first is the mysqli_result object:
I basically just use it to be able to fetch one or more data objects from the result set.
I like to use objects as much as I can. The other class that I wrap is the mysqli_stmt class, which is basically a prepared statement. I have a really simple one at the moment, you can see it here:
As a convention I only use prepared statements for write operations so I don't need to support results from a statement execute() call. The last piece of the puzzle and the point of the entire article is the profiler. Here it is:
Basically all it does it record the start and end times of a query as well as providing a means for getting the explain plans for queries that have already run. It doesn't actually perform the explain queries until you explicitly ask for them, that way i can keep the profiler overhead lower for the default usage. Speaking of usage, here's how I display database debug information:
Now of course you know I don't just vomit this information all over my page, I log it to FirePHP. But that's a topic for another time!