Search code examples
phppythongetattr

PHP approach to python's magic __getattr__()


I was wondering if there was some way in PHP to duplicate some of the magic of Python attribute/key access.

I use a Mongo ORM class written by Steve Lacey called Minimongo in which he utilizes the __getattr__ and __getitem__ to reroute key and attribute flavored access and preserve the 'document-oriented' nature of Mongo. val = doc.foo and val = doc['foo'] become equivalent.

I was wondering if there is a similar interface in PHP that would allow the changing of how object access is handled for a class that inherits from it. I looked through the STL and couldn't find one that filled suit. It would be greatly useful for setting up defaults. Thanks.


Solution

  • Have a look at __get() and __set() and ArrayAccess.

    With the former you can make non-public members accessbile, as in $obj->foo, with the latter you can access them like $obj['foo'].

    You can hardwire them however you like, internally.

    Personally I would suggest you keep these magically-accessible properties into one single array member of the class, so you don't end up with spaghetti code.

    POC:

     1  <?php
     2  class Magic implements ArrayAccess {
     3  
     4      protected $items = array();
     5  
     6      public function offsetExists($key) {
     7          return isset($this->items[$key]);
     8      }
     9      public function offsetGet($key) {
    10          return $this->items[$key];
    11      }
    12      public function offsetSet($key, $value) {
    13          $this->items[$key] = $value;
    14      }
    15      public function offsetUnset($key) {
    16          unset($this->items[$key]);
    17      }
    18  
    19      //do not modify below, this makes sure we have a consistent
    20      //implementation only by using ArrayAccess-specific methods
    21      public function __get($key) {
    22          return $this->offsetGet($key);
    23      }
    24      public function __set($key, $value) {
    25          $this->offsetSet($key, $value);
    26      }
    27      public function __isset($key) {
    28          return $this->offsetExists($key);
    29      }
    30      public function __unset($key) {
    31          $this->offsetUnset($key);
    32      }
    33  }
    34  
    35  //demonstrate the rountrip of magic
    36  $foo = new Magic;
    37  $foo['bar'] = 42;
    38  echo $foo->bar, PHP_EOL;//output 42
    39  $foo->bar++;
    40  echo $foo['bar'];//output 43
    41  
    

    Consistency Milord, exactly as you asked.