Codeigniter中的get_instance():为什么要将它赋给变量?

时间:2011-08-25 18:41:34

标签: php codeigniter singleton reference

在Codeigniter中,get_instance()是一个全局可用的函数,它返回Controller超级对象,它包含所有当前加载的类(它返回Controller类实例)。我将包含当前的源代码:

get_instance()Codeigniter.php

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

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

CI_Controller

中定义了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;
    }
}

以下是建议在user guide for creating libraries中使用的方式:

  

利用库中的CodeIgniter资源

     

要访问库中的CodeIgniter本机资源,请使用   get_instance()功能。此函数返回CodeIgniter super   对象

     

通常在您的控制器功能中,您将调用任何一个   使用$this构造的可用CodeIgniter函数:   $this->load->helper('url'); $this->load->library('session'); $this->config->item('base_url');等。

     然而,

$this只能在您的控制器中直接使用   模型或您的观点。如果您想使用CodeIgniter的类   您可以在自己的自定义类中执行以下操作:

     

首先,将CodeIgniter对象分配给变量:

     

$ CI =& get_instance();

     

将对象分配给变量后,您将使用它   变量而不是$this:       $ CI =& get_instance();       $ CI->负载>辅助( 'URL'); $ CI->负载>库( '会话');       $ CI-> config->项( 'BASE_URL');等

     

注意:您会注意到上面的get_instance()功能正在发生   通过引用传递:

     

$ CI =& get_instance();

     

这非常重要。按引用分配可让您使用   原始的CodeIgniter对象,而不是创建它的副本。

相关帖子:explain $CI =& get_instance(); / Codeigniter: Get Instance

所以,这是我的实际问题:

为什么用户指南建议为变量分配get_instance()?我很确定我理解不通过引用分配的含义,但为什么在get_instance()->load->model()工作正常时建议将它分配给变量?

我在CI中看到很多用户定义的或第三方类,它们分配给对象的属性:

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');
    }
}

可怜的例子,但我经常看到这一点。为什么要使用这种方法而不是直接调用get_instance()似乎就像将整个Controller对象分配给一个类变量一样,即使它是一个引用也不是一个好主意。也许没关系。

我想为get_instance()编写一个包装函数,因此更容易输入,而且我不必经常将它分配给变量。

function CI()
{
    return get_instance();
}

或者:

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

然后我可以从任何地方使用CI()->class->method()而无需将其分配给变量,编写和理解它的功能非常容易,并且可以生成更短,更优雅的代码。

  • 有没有理由不接受这种方法?
  • 以上两个CI()函数之间是否有任何区别?
  • 为什么建议将get_instance()分配给变量而不是直接调用它?
  • &function &get_instance(){}表示定义的位置是什么意思?我对references的含义有所了解,并在适当时使用它们,但我从未见过以这种方式定义的函数。如果我写一个包装函数,我也应该使用它吗?

请注意,这不是一个风格问题,而是技术问题。我想知道是否有任何问题,性能或其他,使用我建议的方法。

编辑:到目前为止,我们已经:

  • 方法链接在php4中不可用,因此分配给变量是一种解决方法(尽管这与Codeigniter已经放弃php4支持相当无关)
  • 不止一次调用函数返回对象的次要开销,而不是调用它一次并分配给变量。

还有其他什么,或者这些是唯一潜在的问题?

7 个答案:

答案 0 :(得分:22)

据我所知,这比方便更重要。您可能会在库中大量使用CI超级对象,那么为什么不将它分配给变量以使其更容易使用?

还有其他一些事情要考虑......

  1. 如果你把这个方法放在一个帮助器中,那么这个方法就成了你正在使用它的任何一个类的依赖。这对你来说可能不是什么大问题,但是如果你想与其他任何人共享库,那么它们可能不是对依赖感到高兴,特别是因为在CI社区中已经有一种标准的处理方法。
  2. 对性能有轻微影响,因为每次使用帮助程序时都要调用get_instance(),而不是将结果存储在变量中。
  3. 由于这是一个应该可以节省时间的辅助方法,对于那些主要在CI的核心MVC文件中工作的人来说,设置这样的帮助器需要更长的时间,而不是仅仅将其设置为少数几个变量。你需要的地方。

答案 1 :(得分:3)

  

为什么建议将get_instance()分配给变量   比直接打电话?

最有可能的是,建议保持与php4的向后兼容性,其中默认情况下对象不是通过引用传递的,而是克隆的。

  

有没有理由不接受这种方法?

仅当您希望应用程序在过时的php安装上运行时

答案 2 :(得分:3)

最近PHP4 CI PHP42.0.0的支持不支持方法链接(来自版本$CI)。另外,每次写get_instance()都比写{{1}}容易。

答案 3 :(得分:3)

必须通过引用进行分配,因为如果创建了另一个类实例,CI_Controller::$instance的值可能会发生变化。构造函数每次运行时都会重新分配self::$instance

一般来说,这感觉就像一个糟糕的设计模式,并且缺少单例的属性,只能将类限制为一个实例http://en.wikipedia.org/wiki/Singleton_pattern

似乎可以输入CI_Controller::get_instance()->$className->$method();,这似乎更符合您要求的CI()->$className->$method

最终,要求只能创建$instance的一个实例才有意义,然后才能消除通过引用分配的需要。

答案 4 :(得分:2)

我更喜欢用这种方式,它很简单

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();
    }
}

答案 5 :(得分:1)

它可能是几件事的组合,包括已经提到的:

  • 向后兼容性
  • 便利
  • 风格指南

最好,我喜欢将这个“推荐”作为风格指南的一部分。也许不是CI的官方风格指南,但仍然。

想象一下,CI的所有第三方脚本都实现了这一建议,任何开发人员都能够快速确定这些脚本的设计方式 - 尽管这只是脚本的一小部分。

IMO最重要的另一件事是方法链的机制 - 而CI()->class->method()对我来说似乎不太直观,知道CI的其余部分是如何工作的。

答案 6 :(得分:0)

从PHP5开始,通过引用获得get_instance()的结果毫无意义。可悲的是,这种坏习惯似乎根深蒂固,所以让我们来处理它。

对于那些感兴趣的人,这里有一个超快速实例getter:

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

    return $CI;
}

请注意,如果静态变量是通过引用分配的,则静态变量不起作用。

此外,您不得通过引用获取此CI()的结果。额外的糖: - )

啊,显然你仍然有功能调用的(轻微)成本。你仍然可能想要使用变量而不是几十次调用函数。