Search code examples
phpautoloadmagic-methods

Hook variable call in PHP


what i'm trying to archive is kind of an autoloader for variables in php. is there any way to hook the loading of variables in php?

example usage would be:

function __autoloadVar($varname,$indices){
    global $$varname;

    if(count($indices) > 0 && !isset($$varname[$indices[0]])){ //first index
        $$varname[$indices[0]] = load_var_content($indices[0]); //this would call a function that loads a variable from the database, or another source
    }
}

echo $foo["bar"]["baz"];
// => calls __autoloadVar("foo",array("bar","baz")) then accessing it

is there any hook to archive this?

[EDIT]: the use case would be that i'm trying to refactor the loading of language properties. they're stored in files, which have become pretty pumped and memory intensive, since they are always completely loaded, even if they're unused.

Exchanging all the variables with a function call would not work, since that would need months to replace everywhere, especially because search and replace won't work if the variables are embedded in strings.

Another refacturing will be to move the variables to the database, which can be done in a script. but the loading process to load all variables at once would hit way too hard in the runtime.


Solution

  • It's possible to make $foo somewhat "magical", if you know its structure:

    class Foo implements ArrayAccess {
      private $bar;
    
      public function offsetGet($name) {
        switch($name) {
          case "bar":
            if(empty($this->bar)) $this->bar = new FooBar;
            return $this->bar;
        }
      }
      public function offsetExists($offset) {  }
      public function offsetSet($offset, $value) {  }
      public function offsetUnset($offset) {  }
    }
    
    class FooBar implements ArrayAccess {
      private $baz;
    
      public function offsetGet($name) {
        switch($name) {
          case "baz":
            if(empty($this->baz)) $this->baz = new FooBarBaz;
            return $this->baz;
        }
      }
      public function offsetExists($offset) {  }
      public function offsetSet($offset, $value) {  }
      public function offsetUnset($offset) {  }
    }
    
    class FooBarBaz {
      public function __toString() {
        return "I'm FooBarBaz\n";
      }
    }
    
    $foo = new Foo;
    echo $foo['bar']['baz'];
    

    What everything is possible with this approach is left as an exercise.