59

In Codeigniter, get_instance() is a globally available function that returns the Controller super-object which contains all the currently loaded classes (it returns the Controller class instance). I'll include the current source code:

get_instance() is defined in Codeigniter.php

// Load the base controller class
require BASEPATH.'core/Controller.php';

function &get_instance()
{
    return CI_Controller::get_instance();
}

And CI_Controller is defined in Controller.php

class CI_Controller {

    private static $instance;

    /**
     * Constructor
     */
    public function __construct()
    {
        self::$instance =& $this;

        // Assign all the class objects that were instantiated by the
        // bootstrap file (CodeIgniter.php) to local class variables
        // so that CI can run as one big super object.
        foreach (is_loaded() as $var => $class)
        {
            $this->$var =& load_class($class);
        }

        $this->load =& load_class('Loader', 'core');

        $this->load->set_base_classes()->ci_autoloader();

        log_message('debug', "Controller Class Initialized");
    }

    public static function &get_instance()
    {
        return self::$instance;
    }
}

Here's how it is recommended to be used in the user guide for creating libraries:

Utilizing CodeIgniter Resources within Your Library

To access CodeIgniter's native resources within your library use the get_instance() function. This function returns the CodeIgniter super object.

Normally from within your controller functions you will call any of the available CodeIgniter functions using the $this construct: $this->load->helper('url'); $this->load->library('session'); $this->config->item('base_url'); etc.

$this, however, only works directly within your controllers, your models, or your views. If you would like to use CodeIgniter's classes from within your own custom classes you can do so as follows:

First, assign the CodeIgniter object to a variable:

$CI =& get_instance();

Once you've assigned the object to a variable, you'll use that variable instead of $this: $CI =& get_instance(); $CI->load->helper('url'); $CI->load->library('session'); $CI->config->item('base_url'); etc.

Note: You'll notice that the above get_instance() function is being passed by reference:

$CI =& get_instance();

This is very important. Assigning by reference allows you to use the original CodeIgniter object rather than creating a copy of it.

Related posts: explain $CI =& get_instance(); / Codeigniter: Get Instance

So, here is my actual question:

Why does the user guide recommend assigning get_instance() to a variable? I'm fairly certain I understand the implications of not assigning by reference, but why is it recommended to assign it to a variable when get_instance()->load->model() works fine?

I see a lot of user defined or third party classes in CI that assign to a property of the object:

class MY_Class {

    private $CI;

    function __construct()
    {
        $this->CI =& get_instance();
    }
    function my_func()
    {
        $this->CI->load->view('some_view');
    }
    function my_other_func()
    {
        $this->CI->load->model('some_model');
    }
}

Poor example, but I see this frequently. Why bother with this method instead of just calling get_instance() directly? It seems like assigning the entire Controller object to a class variable wouldn't be a great idea, even if it is a reference. Maybe it doesn't matter.

I want to write a wrapper function for get_instance() so it's easier to type, and I don't have to constantly assign it to a variable.

function CI()
{
    return get_instance();
}

Or:

function CI()
{
    $CI =& get_instance();
    return $CI;
}

Then I could use CI()->class->method() from anywhere without the hassle of assigning it to a variable, it's very easy to write and understand what it does, and can result in shorter, more elegant code.

  • Is there any reason not to take this approach?
  • Is there any difference between the two CI() functions above?
  • Why is it recommended to assign get_instance() to a variable rather than calling it directly?
  • What does the & in function &get_instance(){} mean where it is defined? I know a bit about what references are for and I use them when appropriate, but I've never seen a function defined this way. If I do write a wrapper function, should I use this as well?

Please note that this is not so much a style question, but a technical one. I want to know if there are any issues, performance or otherwise, with using the method I'm suggesting.

EDIT: So far we have:

  • Method chaining is not available in php4, so assigning to a variable is a workaround (although this is fairly irrelevant as Codeigniter has dropped php4 support)
  • The minor overhead of calling a function more than once to return the object, rather than calling it once and assigning to a variable.

Anything else, or are these the only potential issues?

Community
  • 1
  • 1
Wesley Murch
  • 101,186
  • 37
  • 194
  • 228
  • This is a really really long post for what is essentially a feature request to add a new super-global alias. The user guide suggests using a reference as that is the shorted fastest way for repetitive use, but it doesn't say get_instance()->foo is bad. Do whatever you like. – Phil Sturgeon Sep 12 '11 at 11:43
  • @PhilSturgeon: It's only lengthy because I wanted input from people who aren't familiar with CI, without forcing them to leave this site for the necessary information. It's not even specific to CI, nor is it a feature request, and was mostly to help me understand how (or how not) to work with references on a huge object. – Wesley Murch Dec 23 '11 at 21:53
  • @PhilSturgeon: I honestly still don't fully understand what's going on here, particularly the reference in the function def `function &get_instance()`, and if there is or is not a difference between the two functions I proposed. If you'd like to add a more in-depth answer, I'd be very grateful and happy to accept it. – Wesley Murch Dec 23 '11 at 22:02
  • Simply put, there is literally no difference in the two functions you posted, apart from one is 0.0000001% quicker thanks to the fact you don't have to create a variable to hold the reference. Use either one. – Phil Sturgeon Dec 27 '11 at 15:01
  • Kind of a useless post, if you get here, you don't need to read on. Save your time. – Steve-O-Rama May 03 '13 at 17:11
  • came across this question today when troubleshooting some `get_instance` problems. my issue was the class accessing `get_instance` could be stored in a session. this would cause 'incomplete object' errors. calling `get_instance` again when needed "*fixes*" it, but still hoping for a better solution. – Andrew Brown Apr 06 '14 at 20:28
  • I am using public function __get($var) { return get_instance()->$var; } inplace of $this->CI =& get_instance(); so that I can load methods direct but I believe its not working in latest php version what can be the fix? – Umar Adil Dec 21 '17 at 12:29
  • @WesleyMurch Please consider this post about PSR code styling guidelines: https://stackoverflow.com/a/63914758/2943403 – mickmackusa Sep 16 '20 at 09:58
  • @mickmackusa I'm with ya mate, this was 10 years ago when I was an even worse programmer :) – Wesley Murch Sep 17 '20 at 20:08

7 Answers7

23

As far as I know, it's a matter of convenience more than anything. Chances are that you will be using the CI super object a lot in your libraries so why not assign it to a variable to make it a little easier to work with?

There are a few other things to consider...

  1. If you put this method in a helper, that method becomes a dependency for any class you are using it in. This might not be a big deal for you, but if you want to share libraries with anyone else they may not be happy about the dependency, especially since there is already a standard way of handling this in the CI community.
  2. There is a slight impact on performance because you are calling get_instance() every time you use the helper rather than storing its result in a variable.
  3. Since this is a helper method that is supposed to save you time, for anyone who is working mostly in the core MVC files of CI, setting up a helper like this would take longer than just setting it to a variable in the few places you need it.
Chris Schmitz
  • 8,097
  • 6
  • 31
  • 41
  • "writing these helper methods probably takes longer" Not following you there, I only want to write one function, and it is definitely shorter/easier to use `CI()->do_something(); CI()->do_something_else()` than assigning it to a variable, and shorter than using `$this->CI->do_something()` in a class method. I want to know if there are any problems, performance or otherwise, that this can cause. This answer supports what I want to do, which is nice, but I don't see any facts - only "I think" and "probably". – Wesley Murch Aug 25 '11 at 19:01
  • If it's going to be a single function that you will have access to everywhere you will probably be putting it into a helper. It seems to me that unless you are working outside of the super object a lot the benefits would outweigh the costs (it would take more time to setup the helper than it would save you). – Chris Schmitz Aug 25 '11 at 19:21
  • We work outside the scope of the super object in every library, class, and helper. Take more time? Doesn't make sense to me. I write this tiny function once in a helper file, include it, then it's globally available - even from within other helpers that, for instance, only need to call it once. – Wesley Murch Aug 25 '11 at 19:23
  • Also, there would be a slight impact on performance because you would be redeclaring the super object every time you use your helper method. If you store it in a variable you don't have to run the get_instance() method on every call. – Chris Schmitz Aug 25 '11 at 19:24
  • OK, your last comment makes sense - but that seems to be a small price to pay if that is indeed the only issue (PHP4 support excluded). What about assigning it to a class variable as is commonly done? Wouldn't that have a similar hit on performance or even worse (10 or more included classes with a property that references the Controller object)? Besides, it's still a reference so it doesn't actually recreate the object. It's like saying that simply assigning a variable creates overhead, or am I mistaken? – Wesley Murch Aug 25 '11 at 19:26
  • Yeah, you are just calling a reference to the super object, but your helper method is calling two methods to access it vs just the one when using the native `get_instance()`. Also, you are calling those 2 methods every time vs storing the result once and working with that. It's kind of like caching selectors in jQuery.... I've updated my answer with some of the info from our comments. – Chris Schmitz Aug 25 '11 at 19:46
  • I'm interested most in #2 in your answer, it's fair to say that most of what I write (I work mainly on a CMS that's in it's 4th incarnation) is going to have a lot of dependencies, and a wrapper function is not hard to search/replace if I want the code to be portable. Thanks for the assurance, I'd like to leave this open for a day or two still in case anyone else has something to add. – Wesley Murch Aug 25 '11 at 19:55
  • Yeah, I would still like to hear what others have to say about this too. – Chris Schmitz Aug 25 '11 at 19:58
3

It is necessary to assign by reference because the value of CI_Controller::$instance is subject to change if another instance of the class is created. The constructor re-assigns self::$instance each time it runs.

In general, this feels like a bad design pattern and is missing the property of a singleton that limits the class to only one instance, http://en.wikipedia.org/wiki/Singleton_pattern.

It seems possible to type, CI_Controller::get_instance()->$className->$method(); which does seem like more typing that your requested CI()->$className->$method.

Ultimately, it would make sense to require that only one instance of $instance can be created and then the need for assigning by reference would be eliminated.

Ben
  • 1,620
  • 18
  • 11
3

Why is it recommended to assign get_instance() to a variable rather than calling it directly?

Most probably, it is recommended to maintain backward compatibility with php4, where objects were not passed by reference by default, but were cloned.

Is there any reason not to take this approach?

Only if you want your application to run on outdated php installations

dev-null-dweller
  • 29,274
  • 3
  • 65
  • 85
3

Method chaining is not supported in PHP4 and CI dropped support for PHP4 very recently (from version 2.0.0). Also it's easy to write $CI than writing get_instance() every time.

The Alpha
  • 143,660
  • 29
  • 287
  • 307
Muhammad Usman
  • 12,439
  • 6
  • 36
  • 59
  • ..but it's easier to write `CI()` in a class than writing a `__construct()` just to assign `get_instance()` to a class property (say `$CI`), along with `private $CI;` and calling `$this->CI`. Good point about method chaining though, I wonder if this is the only technical reason? – Wesley Murch Aug 25 '11 at 19:19
  • You are right in that way, but method chaining is the main reason I think. BTW `__construct` is not only for this it has to call `parent::__construct();` also. – Muhammad Usman Aug 25 '11 at 20:07
  • That only makes sense for classes that have a parent and still is not strictly necessary (only if you actually want to construct the parent class), and it's not the case in most (if not all) CI libraries. – Wesley Murch Aug 25 '11 at 20:09
2

I prefer uses this way, it's simple

class Test
{
    //magic method __get, whit this can use $this->load
    //instead create a variable ci, then do $this->ci->load, cool :)

    public function __get($var)
    {
        return get_instance()->$var;
    }

    public function showUrl()
    {
        $this->load->helper("url");
        echo base_url();
    }
}
Jazi
  • 6,569
  • 13
  • 60
  • 92
1

It could be a combination of several things, including the already mentioned:

  • Backwards compatibility
  • Convenience
  • Style Guide

Preferably, I like the idea of this 'recommendation' as being a part of a style guide. Maybe not the official style guide of CI, but still.

Imagine that all third-party scripts for CI implements this recommendation, any developer would be able to quickly determine how these scripts are designed - although this just being a very small part of the script.

Another thing that IMO is important is the mechanics of method chaining - and doing CI()->class->method() wouldn't seem intuitive for me, knowing how the rest of CI works.

Repox
  • 15,015
  • 8
  • 54
  • 79
  • If it's *only* a style or convenience recommendation, then I'm happy to hear it - backwards compat is not an issue for me. I don't particularly care for following the suggested style here, every library I've written (about 12) has a `$CI` property that references `get_instance()`, it's fairly tedious and ugly. I wonder if this is merely a style concern? – Wesley Murch Aug 25 '11 at 19:08
  • Well, I for one like the $CI property. The idea of writing get_instance() and refering to this everytime would be timeconsuming for me, considering the style I usually write in. But I don't see any problem in doing so. It's propably just a matter of 'religion' if you know what I mean. – Repox Aug 25 '11 at 19:51
0

Getting the result of get_instance() by reference just makes no sense since PHP5. Sadly this bad habit seems to be deep-rooted, so let's just deal with it.

For those interested, here's an über fast instance getter:

function CI()
{
    static $CI;
    isset($CI) || $CI = CI_Controller::get_instance();

    return $CI;
}

Note that the static variable wouldn't work if it were assigned by reference.

Also, you are forced not to get by reference the result of this CI(). Extra sugar :-)

Ah, and obviously you still have the (slight) cost of the function call. You still may want to use a variable instead of calling the function dozens of times.

Gras Double
  • 15,901
  • 8
  • 56
  • 54