web-dev-qa-db-fra.com

get_instance () dans Codeigniter: Pourquoi l'assigner à une variable?

Dans Codeigniter, get_instance() est une fonction disponible à l'échelle mondiale qui renvoie le super-objet Controller qui contient toutes les classes actuellement chargées (elle renvoie l'instance de classe Controller). Je vais inclure le code source actuel:

get_instance() est définie dans Codeigniter.php

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

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

Et CI_Controller Est défini dans 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;
    }
}

Voici comment il est recommandé de l'utiliser dans le guide de l'utilisateur pour la création de bibliothèques :

Utilisation des ressources CodeIgniter dans votre bibliothèque

Pour accéder aux ressources natives de CodeIgniter dans votre bibliothèque, utilisez la fonction get_instance(). Cette fonction renvoie le super-objet CodeIgniter.

Normalement, à partir des fonctions de votre contrôleur, vous appellerez l'une des fonctions CodeIgniter disponibles en utilisant la construction $this: $this->load->helper('url'); $this->load->library('session'); $this->config->item('base_url'); etc.

$this, Cependant, ne fonctionne que directement dans vos contrôleurs, vos modèles ou vos vues. Si vous souhaitez utiliser les classes de CodeIgniter à partir de vos propres classes personnalisées, vous pouvez le faire comme suit:

Tout d'abord, affectez l'objet CodeIgniter à une variable:

$ CI = & get_instance ();

Une fois que vous avez affecté l'objet à une variable, vous utiliserez cette variable au lieu de $this: $ CI = & get_instance (); $ CI-> load-> helper ('url'); $ CI-> load-> bibliothèque ('session'); $ CI-> config-> item ('base_url'); etc.

Remarque: vous remarquerez que la fonction get_instance() ci-dessus est transmise par référence:

$ CI = & get_instance ();

Ceci est très important. L'affectation par référence vous permet d'utiliser l'objet CodeIgniter d'origine plutôt que d'en créer une copie.

Articles connexes: expliquer $ CI = & get_instance (); / Codeigniter: Get Instance

Voici donc ma vraie question:

Pourquoi le guide de l'utilisateur recommande-t-il d'affecter get_instance() à une variable? Je suis assez certain de comprendre les implications de ne pas attribuer par référence, mais pourquoi est-il recommandé de l'affecter à une variable lorsque get_instance()->load->model() fonctionne correctement?

Je vois beaucoup de classes définies par l'utilisateur ou tierces dans CI qui affectent à une propriété de l'objet:

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

Pauvre exemple, mais je le vois souvent. Pourquoi s'embêter avec cette méthode au lieu d'appeler simplement get_instance() directement? Cela semble comme affecter tout l'objet Controller à une variable de classe ne serait pas une bonne idée, même s'il s'agit d'une référence. Peut-être que cela n'a pas d'importance.

Je veux écrire une fonction wrapper pour get_instance() donc c'est plus facile à taper, et je n'ai pas à l'assigner constamment à une variable.

function CI()
{
    return get_instance();
}

Ou:

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

Ensuite, je pourrais utiliser CI()->class->method() de n'importe où sans avoir à l'assigner à une variable, il est très facile d'écrire et de comprendre ce qu'il fait, et peut entraîner un code plus court et plus élégant.

  • Y a-t-il une raison de ne pas adopter cette approche?
  • Y a-t-il une différence entre les deux fonctions CI() ci-dessus?
  • Pourquoi est-il recommandé d'affecter get_instance() à une variable plutôt que de l'appeler directement?
  • Que signifie & Dans function &get_instance(){} où il est défini? Je sais un peu à quoi servent références et je les utilise le cas échéant, mais je n'ai jamais vu une fonction définie de cette façon. Si j'écris une fonction wrapper, dois-je également l'utiliser?

Veuillez noter qu'il ne s'agit pas tant d'une question de style que d'une question technique. Je veux savoir s'il y a des problèmes, performances ou autre, en utilisant la méthode que je suggère.

[~ # ~] modifier [~ # ~] : Jusqu'à présent, nous avons:

  • Le chaînage de méthode n'est pas disponible dans php4, donc l'affectation à une variable est une solution de contournement (bien que cela soit peu pertinent car Codeigniter a abandonné la prise en charge de php4)
  • La surcharge mineure d'appeler une fonction plus d'une fois pour renvoyer l'objet, plutôt que de l'appeler une fois et de l'assigner à une variable.

Autre chose, ou sont-ce les seuls problèmes potentiels?

58
Wesley Murch

Pour autant que je sache, c'est une question de commodité plus que tout. Il y a de fortes chances que vous utilisiez beaucoup le super-objet CI dans vos bibliothèques, alors pourquoi ne pas l'attribuer à une variable pour le rendre un peu plus facile à utiliser?

Il y a quelques autres choses à considérer ...

  1. Si vous mettez cette méthode dans une aide, cette méthode devient une dépendance pour n'importe quelle classe dans laquelle vous l'utilisez. Cela peut ne pas être un gros problème pour vous, mais si vous souhaitez partager des bibliothèques avec quelqu'un d'autre, ils peuvent ne pas être satisfaits de la dépendance, d'autant plus qu'il existe déjà un moyen standard de gérer cela dans la communauté CI.
  2. Il y a un léger impact sur les performances car vous appelez get_instance() chaque fois que vous utilisez l'assistant plutôt que de stocker son résultat dans une variable.
  3. Puisqu'il s'agit d'une méthode d'aide qui est censée vous faire gagner du temps, pour quiconque travaille principalement dans les fichiers MVC principaux de CI, la configuration d'un assistant comme celui-ci prendrait plus de temps que de le définir sur une variable dans les quelques endroits dont vous avez besoin il.
22
Chris Schmitz

Il est nécessaire de l'attribuer par référence car la valeur de CI_Controller::$instance Est susceptible de changer si une autre instance de la classe est créée. Le constructeur réaffecte self::$instance À chaque exécution.

En général, cela ressemble à un mauvais modèle de conception et il manque la propriété d'un singleton qui limite la classe à une seule instance, http://en.wikipedia.org/wiki/Singleton_pattern .

Il semble possible de taper, CI_Controller::get_instance()->$className->$method(); qui semble être plus typé que votre CI()->$className->$method demandé.

En fin de compte, il serait logique d'exiger qu'une seule instance de $instance Puisse être créée, puis le besoin d'attribution par référence serait éliminé.

3
Ben

Pourquoi est-il recommandé d'affecter get_instance () à une variable plutôt que de l'appeler directement?

Très probablement, il est recommandé de maintenir la compatibilité descendante avec php4, où les objets n'étaient pas passés par référence par défaut, mais étaient clonés.

Y a-t-il une raison de ne pas adopter cette approche?

Uniquement si vous souhaitez que votre application s'exécute sur des installations php obsolètes

3
dev-null-dweller

Le chaînage de méthodes n'est pas pris en charge dans PHP4 Et CI a abandonné la prise en charge de PHP4 Très récemment (à partir de la version 2.0.0). Il est également facile d'écrire $CI Que d'écrire get_instance() à chaque fois.

3
Muhammad Usman

Je préfère les utilisations de cette façon, c'est 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();
    }
}
2
user2604283

Cela pourrait être une combinaison de plusieurs choses, y compris celles déjà mentionnées:

  • Rétrocompatibilité
  • Commodité
  • Guide de style

De préférence, j'aime l'idée de cette "recommandation" comme faisant partie d'un guide de style. Peut-être pas le guide de style officiel de CI, mais quand même.

Imaginez que tous les scripts tiers pour CI implémentent cette recommandation, tout développeur serait en mesure de déterminer rapidement comment ces scripts sont conçus - bien que ce ne soit qu'une très petite partie du script.

Une autre chose que l'OMI est importante est la mécanique du chaînage des méthodes - et faire CI()->class->method() ne me semble pas intuitif, sachant comment fonctionne le reste de CI.

1
Repox

Obtenir le résultat de get_instance() par référence n'a aucun sens depuis PHP5. Malheureusement, cette mauvaise habitude semble être profondément enracinée, alors traitons-la.

Pour les personnes intéressées, voici un getter d'instance über rapide:

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

    return $CI;
}

Notez que la variable statique ne fonctionnerait pas si elle était affectée par référence.

De plus, vous êtes obligé de ne pas obtenir par référence le résultat de cette CI(). Sucre supplémentaire :-)

Ah, et évidemment vous avez toujours le (léger) coût de l'appel de fonction. Vous pouvez toujours vouloir utiliser une variable au lieu d'appeler la fonction des dizaines de fois.

0
Gras Double