CodeIgniter: Global Vars via Controller and Indire

2019-09-05 04:40发布

问题:

A problem haunting me since early days of CodeIgniter and now, with the new CI 3 i want to see if there is a more elegant way to solve it.

// file: application/core/MY_Controller.php
class MY_Controller extends CI_Controller {

   public $GLO;

   function __construct(){
      parent::__construct();
      $this->GLO['foo'] = 'bar';
      $this->GLO['arr'] = array();
   }
}

then, later in the code, I need to get and set the values of the $GLO variable dynamically. So for instance:

// file: application/controllers/dispatcher.php
class Dispatcher extends MY_Controller {

   function __construct() {
     parent::__construct();
     $this->load->model('public/langs');
     print_r($this->GLO);
   }
}

will print array('foo'=>'bar, 'arr'=>Array()) which is correct. Also in my models I can get the values of the $GLO array in the same manner. However, as soon as I need to set any values in the $GLO array, I get the Indirect modification of overloaded property notice and so I am stuck. In my model (after executing a DB query):

// file: application/models/public/langs.php
class Langs extends CI_Model {

function __construct(){
    parent::__construct();  
}

function set_global_languages(){
  print_r($this->GLO); // <<< prints the same values as in the controller above
  $temp = array();
  // [stripped db code]
  $temp['label'] = $row->label;
  $temp['id'] = $row->id;      
  $this->GLO['arr'][] = $temp; // <<< this is where the notice happens
}

Any clues of how I can use $this->GLO['foo'] = 'baz'; for setting properties of this global array in my models?

Cheers.

回答1:

I stumbled upon this problem a ton of times. Since you are asking for an elegant solution - i try to give you some idea.

There is a library called Registry, which is written totally fine and can be extended any time. You can find the library here.

Put it in your libraries folder. This library should get autoloaded so it is always available. Add it to your config/autoload.php

$autoload['libraries'] = array(...,"Registry");

After that you should have a really easy way of storing things globally within CI - in your code for example it would look like

class MY_Controller extends CI_Controller {

    function __construct()
    {
        parent::__construct();

        $arrSomething = [
            'foo' => "bar",
            "arr" => array()
        ];
        $this->registry->set("arrSomething",$arrSomething);
    }
}

class Dispatcher extends MY_Controller 
{

    function __construct() 
    {
        parent::__construct();
        $this->load->model('public/langs');
    }
}

class Langs extends CI_Model 
{

    function __construct(){
        parent::__construct();  
    }

    function set_global_languages()
    {
        $arrSomething = $this->registry->get("arrSomething");
        $temp = array();
        // [stripped db code]
        $temp['label'] = $row->label;
        $temp['id'] = $row->id;      
        $arrSomething['arr'][] = $temp;

        //in case of an array i guess you've to reset it because there is no reference or try to call it by reference with "&"
        $this->registry->set("arrSomething");

    }
}


回答2:

sintakonte, thanks a lot for the tip. Last night I had to rewrite a lot of code to see if and how it works. The Registry class works as expected! The only issue with this set/get method is the handling of deep arrays, especially those created dynamically and having their data pushed dynamically too. So today morning I did something very bad :) and just created this class:

class Globals {
  public $data = array();
}

So now I am going from $this->GLO['foo'] to $this->globals->data['foo'] and get to keep existing syntax intact! It also enables me to reuse the class in different controllers and models under different names, once initializing it as "globals" and the other time as "admin". Seems to work alright, too!