Sunday, March 18, 2012

Codeigniter load->model and load->library ideosyncracies

Codeigniter's load model and load library commands both create Singletons, which are global in scope.  This can produce difficult to diagnose bugs if you don't realize it.

When you execute a $this->load->model('model_name', 'instance_name') , it invokes the "model" method in the CI_Loader class.  This method first checks that no other instance of the model exists with the same name.  If you do not give a name, then it uses "model_name" as the "instance_name".  This method stores the name of every model it has created in an array named "_ci_models".  If it does not find the name there, it then looks for it in $CI which is the super object you access via "$CI=& get_instance();". 

Because the model method executes an "if (isset($CI->name))" prior to instantiating the class, there cannot be any any object of any type anywhere within codeigniter that has the same name.  Hence it is global in scope.

And you cannot overwrite the assignment directly.  So let's say for example we are trying to make a "$Vendor_details" object.  And we want to assign one of two different address storage models to it based on the "$vendor_type".  So we create code something like the following.

switch ($vendor_type) {

case "domestic" :
$this->load->model('models/vendor_domestic', 'vendorModel');
break;
case "international" :
$this->load->model('models/vendor_international', 'vendorModel');
break;
...

And we try to access this model via "$this->vendorModel->someFunction".  Let's say the first time through, "vendorModel" is set to reference an instance of "Vendor_domestic", but the next time through, $vendor_type = "international".  We try to create an instance of  the "Vendor_international" model and assign it to $this->vendorModel.  We will get no warning, but we will in fact end up accessing the "Vendor_domestic" instance we created in the first pass, because "$this->vendorModel" cannot be reassigned, and it is pointing to the instance we first created. 

Once the name checks pass, the model method executes a "require_once" on the model name and then creates an instance of it references to either "instance_name" or the model name if no "instance_name" argument was passed in.   It also opens the database connection. 

The library load operates in a very similar way, but of course it does not open the database (which is probably already open anyway in most cases). 

If you need multiple copies of a model or library, you will need to instantiate them by including the referenced class in the top of the file with a:
require_once('path/modelName.php') in the top of the file

and instantiate the class with the standard:
$instance_name = new modelClassName();

No comments:

Post a Comment