get_instance () в Codeigniter: зачем присваивать его переменной? - PullRequest
58 голосов
/ 25 августа 2011

В 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;
    }
}

Вот как рекомендуется использовать в руководстве пользователя для создания библиотек :

Использование ресурсов CodeIgniter в вашей библиотеке

Для доступа к собственным ресурсам CodeIgniterв вашей библиотеке используйте функцию get_instance().Эта функция возвращает суперобъект CodeIgniter.

Обычно из функций вашего контроллера вы вызываете любую из доступных функций CodeIgniter, используя конструкцию $this: $this->load->helper('url'); $this->load->library('session'); $this->config->item('base_url'); и т. Д.

$thisоднако работает только непосредственно с контроллерами, моделями или представлениями.Если вы хотите использовать классы CodeIgniter из своих собственных пользовательских классов, вы можете сделать это следующим образом:

Сначала назначьте объект CodeIgniter переменной:

$ CI = & get_instance ();

Как только вы присвоите объект переменной, вы будете использовать эту переменную вместо $this: $ CI = & get_instance ();$ CI-> load-> помощник ( 'URL');$ CI-> load-> библиотека ( 'сессии');$ CI-> config-> пункт ( 'base_url');и т. д.

Примечание. Вы заметите, что указанная выше функция get_instance() передается по ссылке:

$ CI = & get_instance ();

Это очень важно. Назначение по ссылке позволяет использовать исходный объект CodeIgniter, а не создавать его копию.

Связанные публикации: объяснение $ CI = & get_instance (); / Codeigniter: Get Instance

Итак, вот мой актуальный вопрос:

Почему руководство пользователя рекомендует присваивать get_instance() переменной?Я вполне уверен, что понимаю последствия не назначения по ссылке, но почему рекомендуется присваивать его переменной, когда get_instance()->load->model() работает нормально?

Я вижу много пользовательских или сторонних классовв КИ, которые присваивают свойству объекта:

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(){}, где она определена?Я немного знаю о том, для чего ссылки , и я использую их, когда это уместно, но я никогда не видел функции, определенной таким образом.Если я напишу функцию-обертку, должен ли я ее использовать?

Обратите внимание, что это не столько вопрос style , сколько технический вопрос.Я хочу знать, есть ли какие-либо проблемы, производительность или иным образом , с использованием метода, который я предлагаю.

РЕДАКТИРОВАТЬ : Пока у нас есть:

  • Объединение методов недоступно в php4, поэтому присвоение переменной является обходным решением (хотя это довольно неактуально, поскольку Codeigniter прекратил поддержку php4)
  • Незначительные накладные расходы при вызове функции более одного раза для возврата объекта, а не при вызове его один раз и присвоении переменной.

Что-нибудь еще, или это единственные потенциальные проблемы?

Ответы [ 7 ]

22 голосов
/ 25 августа 2011

Насколько я знаю, это вопрос удобства больше всего на свете. Скорее всего, вы будете часто использовать суперобъект CI в своих библиотеках, так почему бы не назначить его переменной, чтобы с ним было немного легче работать?

Есть еще несколько вещей, которые следует учитывать ...

  1. Если вы поместите этот метод в помощник, этот метод станет зависимостью для любого класса, в котором вы его используете. Это может не иметь большого значения для вас, но если вы хотите поделиться библиотеками с кем-то еще, они могут не быть доволен зависимостью, тем более что в сообществе CI уже есть стандартный способ решения этой проблемы.
  2. Это оказывает небольшое влияние на производительность, потому что вы вызываете get_instance() каждый раз, когда используете помощника, а не сохраняете его результат в переменной.
  3. Поскольку это вспомогательный метод, который должен сэкономить ваше время, для тех, кто работает в основном с основными файлами MVC CI, установка вспомогательного средства, подобного этому, займет больше времени, чем просто установка его в качестве переменной в нескольких места вам это нужно.
3 голосов
/ 27 июля 2012

Необходимо назначить по ссылке, поскольку значение CI_Controller::$instance может быть изменено, если будет создан другой экземпляр класса.Конструктор повторно присваивает self::$instance при каждом запуске.

В общем, это похоже на шаблон плохого проектирования и отсутствует свойство синглтона, которое ограничивает класс только одним экземпляром, http://en.wikipedia.org/wiki/Singleton_pattern.

Кажется возможным набрать CI_Controller::get_instance()->$className->$method();, что выглядит как набрав больше, чем запрашиваемый CI()->$className->$method.

В конечном счете, имеет смысл требовать, чтобы только один экземпляр $instance могбудет создан, и тогда необходимость назначения по ссылке будет устранена.

3 голосов
/ 25 августа 2011

Объединение методов не поддерживается в PHP4, а CI совсем недавно прекратил поддержку PHP4 (с версии 2.0.0). Также легко написать $CI, чем писать get_instance() каждый раз.

3 голосов
/ 25 августа 2011

Почему рекомендуется назначать get_instance () переменной чем звонить напрямую?

Скорее всего, рекомендуется поддерживать обратную совместимость с php4, когда объекты по умолчанию не передаются по ссылке, а клонируются.

Есть ли причина не использовать этот подход?

Только если вы хотите, чтобы ваше приложение запускалось на устаревших установках php

2 голосов
/ 22 июля 2015

Я предпочитаю использовать этот способ, это просто

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();
    }
}
1 голос
/ 25 августа 2011

Это может быть сочетание нескольких вещей, в том числе уже упомянутых:

  • Обратная совместимость
  • Удобство
  • Руководство по стилю

Предпочтительно, мне нравится идея этой «рекомендации» как части руководства по стилю.Возможно, не официальное руководство по стилю CI, но все же.

Представьте, что все сторонние сценарии для CI реализуют эту рекомендацию, любой разработчик сможет быстро определить, как эти сценарии разработаны - хотя это простоочень маленькая часть сценария.

Еще одна вещь, которая важна для IMO, - это механика цепочки методов - и выполнение CI()->class->method() не будет для меня интуитивно понятным, зная, как работает остальная часть CI.

0 голосов
/ 29 июня 2013

Получение результата get_instance() по ссылке просто не имеет смысла, начиная с PHP5.К сожалению, эта вредная привычка, похоже, глубоко укоренилась, поэтому давайте просто с ней разберемся.

Для тех, кто заинтересован, вот очень быстрый метод получения экземпляра:

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

    return $CI;
}

Обратите внимание, что статическая переменнаяне работает, если он был назначен по ссылке.

Кроме того, вы вынуждены не получать по ссылке результат этого CI().Дополнительный сахар: -)

Ах, и, очевидно, у вас все еще есть (небольшая) стоимость вызова функции.Вы все еще можете использовать переменную вместо того, чтобы вызывать функцию десятки раз.

...