Jul 9, 2010

Singleton mysqli Class

Since mysqli is fully object oriented, the most obvious approach to using it is to create a singleton:

Class Db extends mysqli { }

Write a public static getInstance method to return an instance of Db so you get access to all of mysqli's properties and methods while ensuring that mysqli is instantiated only once throughout your application. Sounds straightforward enough.

I was half successful with this approach. I had a line of code like this in the parent class for all of my models:

Public $db = new Db::getInstance();

Then, to call any of mysqli's methods or properties, I would use code like this within my child model classes:

$this->db-> query();

This is where it gets really strange. This technique worked great when calling mysqli's static methods and properties, but would not work at all when calling methods and properties that required an instance of mysqli. For example, calling:

$this->db->affected_rows() gives the following error:

Call to a member function affected_rows() on a non-object

Query is a static method, while affected_rows is an instance method (I tried calling several other static and instance methods; the results were consistent: static methods worked, instance methods didn't). Why would static methods work but not instance methods? In my singleton class, I am returning an instance of mysql, so all of the instance methods should work.

Is this me being boneheaded, or is it a bug in PHP? Viewing the bug tracking system, I noticed that there were some problems when a class extended built-in classes such as mysqli, but those issues have been resolved.

After spending almost two full days working on database implementation, I'm almost ready to go the easy way out and use a global variable to store the mysqli object. The normal concern about unintentionally changing the value of the global variable is totally manageable if I maintain discipline in my code. The one drawback of this approach is that I'll be using a DB connection even when I don't need to. With a singleton, I was using a DB connection only when a model was instantiated, which does not happen on every request.

Other frameworks I've used, including CakePHP, CodeIgniter, and Kohana, always connect to the database for every request, and I don't think the performance hit from this will be significant, especially if I use persistent connections. Also, the vast majority of requests will require a database connection; only a few will not. So global variable it is.

No comments:

Post a Comment