Подтвердить что ты не робот

Get_instance() в Codeigniter: зачем назначать его переменной?

В 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 super объект.

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

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

EDIT: До сих пор мы имеем:

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Есть ли причина не принимать такой подход?

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

Ответ 3

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

Ответ 4

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

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

Ответ 7

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

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

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

    return $CI;
}

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

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

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