4

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.

Flavius
  • 13,566
  • 13
  • 80
  • 126
DeaconDesperado
  • 9,977
  • 9
  • 47
  • 77

2 Answers2

9

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.

Flavius
  • 13,566
  • 13
  • 80
  • 126
  • This worked perfectly. Basically what I was looking to do was make a class that could take a stdClass from a call to json_decode and allow this kind of access but return false by default if a key didnt exist. Schemaless data definitely requires this. It really lifts a burden that have this failsafe in my PHP now... I love it in Python. – DeaconDesperado Jan 05 '12 at 13:36
2

You should have a look at the Magic Methods of PHP: http://php.net/manual/en/language.oop5.magic.php

__get(), __set() and __call() could do what you want.

TimWolla
  • 31,849
  • 8
  • 63
  • 96