get_instance php codeigniter singleton reference

php - get_instance - get instance codeigniter



get_instance() en Codeigniter: ¿Por qué asignarlo a una variable? (7)

¿Por qué se recomienda asignar get_instance () a una variable en lugar de llamarlo directamente?

Lo más probable es que se recomiende mantener la compatibilidad con php4, donde los objetos no se pasaban por referencia de forma predeterminada, sino que se clonaban.

¿Hay alguna razón para no tomar este enfoque?

Solo si desea que su aplicación se ejecute en instalaciones de php obsoletas

En Codeigniter, get_instance() es una función disponible globalmente que devuelve el superobjeto del controlador que contiene todas las clases cargadas actualmente (devuelve la instancia de la clase Controller). Incluiré el código fuente actual:

get_instance() se define en Codeigniter.php

// Load the base controller class require BASEPATH.''core/Controller.php''; function &get_instance() { return CI_Controller::get_instance(); }

Y CI_Controller se define en 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; } }

A continuación, le indicamos cómo se recomienda su uso en la guía del usuario para crear bibliotecas :

Utilizando recursos CodeIgniter dentro de su biblioteca

Para acceder a los recursos nativos de CodeIgniter dentro de su biblioteca, use la función get_instance() . Esta función devuelve el súper objeto CodeIgniter.

Normalmente, desde las funciones de su controlador llamará a cualquiera de las funciones CodeIgniter disponibles usando $this constructo: $this->load->helper(''url''); $this->load->library(''session''); $this->config->item(''base_url''); $this->load->helper(''url''); $this->load->library(''session''); $this->config->item(''base_url''); etc.

$this , sin embargo, solo funciona directamente dentro de sus controladores, sus modelos o sus puntos de vista. Si desea utilizar las clases de CodeIgniter desde sus propias clases personalizadas, puede hacerlo de la siguiente manera:

Primero, asigne el objeto CodeIgniter a una variable:

$ CI = & get_instance ();

Una vez que haya asignado el objeto a una variable, usará esa variable en lugar de $this : $ CI = & get_instance (); $ CI-> load-> helper (''url''); $ CI-> load-> library (''session''); $ CI-> config-> item (''base_url''); etc.

Nota: Notará que la función get_instance() se pasa por referencia:

$ CI = & get_instance ();

Esto es muy importante. Asignar por referencia le permite usar el objeto CodeIgniter original en lugar de crear una copia del mismo.

Publicaciones relacionadas: explicar $ CI = & get_instance (); / Codeigniter: obtener instancia

Entonces, aquí está mi pregunta real:

¿Por qué la guía del usuario recomienda asignar get_instance() a una variable? Estoy bastante seguro de que entiendo las implicaciones de no asignar por referencia, pero ¿por qué se recomienda asignarlo a una variable cuando get_instance()->load->model() funciona bien?

Veo muchas clases definidas por el usuario o de terceros en CI que asignan a una propiedad del objeto:

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

Pobre ejemplo, pero veo esto con frecuencia. ¿Por qué molestarse con este método en lugar de simplemente llamar a get_instance() directamente? Parece que la asignación de todo el objeto Controller a una variable de clase no sería una gran idea, incluso si es una referencia. Tal vez no importa.

Quiero escribir una función de contenedor para get_instance() para que sea más fácil escribir, y no tengo que asignarlo constantemente a una variable.

function CI() { return get_instance(); }

O:

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

Entonces podría usar CI()->class->method() desde cualquier lugar sin la molestia de asignarlo a una variable, es muy fácil escribir y comprender lo que hace, y puede dar como resultado un código más corto y elegante.

  • ¿Hay alguna razón para no tomar este enfoque?
  • ¿Hay alguna diferencia entre las dos funciones de CI() anteriores?
  • ¿Por qué se recomienda asignar get_instance() a una variable en lugar de llamarlo directamente?
  • ¿Qué significa la function &get_instance(){} & en function &get_instance(){} donde se define? Sé un poco sobre para qué sirven las references y las uso cuando sea apropiado, pero nunca he visto una función definida de esta manera. Si escribo una función de contenedor, ¿debería usar esto también?

Tenga en cuenta que esto no es tanto una cuestión de estilo , sino una técnica. Quiero saber si hay algún problema, rendimiento o no , con el uso del método que estoy sugiriendo.

EDITAR : Hasta ahora tenemos:

  • El encadenamiento de métodos no está disponible en php4, por lo que la asignación a una variable es una solución alternativa (aunque esto es bastante irrelevante ya que Codeigniter ha dejado de admitir php4)
  • La sobrecarga menor de llamar a una función más de una vez para devolver el objeto, en lugar de llamarlo una vez y asignarle una variable.

¿Algo más, o son estos los únicos problemas potenciales?


El encadenamiento de métodos no es compatible con PHP4 y CI abandonó el soporte para PHP4 muy recientemente (a partir de la versión 2.0.0 ). También es fácil escribir $CI que escribir get_instance() cada vez.


Es necesario asignar por referencia porque el valor de CI_Controller::$instance está sujeto a cambios si se crea otra instancia de la clase. El constructor reasigna self::$instance cada vez que se ejecuta.

En general, esto se siente como un mal patrón de diseño y le falta la propiedad de un singleton que limita la clase a una sola instancia, http://en.wikipedia.org/wiki/Singleton_pattern .

Parece posible escribir, CI_Controller::get_instance()->$className->$method(); que parece más tipear que su CI()->$className->$method solicitado.

En última instancia, tendría sentido exigir que solo se pueda crear una instancia de $instance y luego se elimine la necesidad de asignar por referencia.


Hasta donde yo sé, es una cuestión de conveniencia más que nada. Lo más probable es que va a utilizar mucho el súper objeto CI en sus bibliotecas, entonces ¿por qué no asignarlo a una variable para que sea más fácil trabajar con él?

Hay algunas otras cosas a considerar ...

  1. Si coloca este método en una ayuda, ese método se convierte en una dependencia para cualquier clase en la que lo esté usando. Esto puede no ser un gran problema para usted, pero si desea compartir bibliotecas con cualquier otra persona, puede que no estén contentos con la dependencia, especialmente porque ya existe una forma estándar de manejar esto en la comunidad de CI.
  2. Hay un ligero impacto en el rendimiento porque llama a get_instance() cada vez que usa el helper en lugar de almacenar su resultado en una variable.
  3. Dado que se trata de un método de ayuda que se supone que le ahorrará tiempo, para cualquier persona que trabaje principalmente en los archivos MVC básicos de CI, configurar un ayudante como este llevaría más tiempo que simplemente establecerlo en una variable en los pocos lugares que necesita eso.

Obtener el resultado de get_instance() por referencia simplemente no tiene sentido desde PHP5. Lamentablemente, este mal hábito parece estar profundamente arraigado, así que simplemente tratemos con eso.

Para aquellos interesados, aquí hay un getter über rápida instancia:

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

Tenga en cuenta que la variable estática no funcionaría si se asignara por referencia.

Además, se ve obligado a no obtener por referencia el resultado de este CI() . Azúcar extra :-)

Ah, y obviamente todavía tienes el (ligero) costo de la llamada a la función. Aún puede querer usar una variable en lugar de llamar a la función docenas de veces.


Podría ser una combinación de varias cosas, incluida la ya mencionada:

  • Compatibilidad al revés
  • Conveniencia
  • Guía de estilo

Preferiblemente, me gusta la idea de esta ''recomendación'' como parte de una guía de estilo. Tal vez no sea la guía de estilo oficial de CI, pero aún así.

Imagínese que todos los scripts de terceros para CI implementan esta recomendación, cualquier desarrollador podría determinar rápidamente cómo se diseñan estos scripts, aunque esto solo representa una parte muy pequeña del script.

Otra cosa que IMO es importante es la mecánica del método de encadenamiento, y hacer CI()->class->method() no me parecería intuitivo, ya que sé cómo funciona el resto de CI.


Prefiero usos de esta manera, es 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(); } }