Proxy pattern with PHP 5

PHP from version 5 on provides reasonable object support. Well the language is not really object-oriented, but hey, it's a scripting language!

Recently I had the chance to implement the proxy pattern (one of my favourite design patterns) in PHP. My goal was to make object relations more dynamical. Lets start from a simple assumption of two kinds of objects:

class Parent {
 var $ID;
 var $Child;
}
 
class Child {
 var $ID;
 var $Parent;
}

As you'll notice, both classes reference each other. Parent points at Child and Child points to Parent.

In case a Parent is instantiated:

$pi = new Parent();

...we receive a parent instance ($pi). As I am a lazy guy, I thought about how could I make the Child at $pi->Child be loaded on demand, so I won't have to instantiate the Child explicitely in case I'd like to use it. Loading objects on demand is exactly what the Proxy Design Pattern recomments.

PHP 5 doesn't provide real properties, but it has two interesting "magic methods": __get() and __set() ...compared to real properties, they have a certain drawback: they are too dynamic!

__get() and __set() signatures

function __get($name); // get virtual property named $name
function __set($name,$value); // set virtual property named $name with the value of $value

Get and set are generic callbacks. They get called on any unknown (one may call it virtual) member of a class. The IDE your using will therefore not be able to provide the $name of virtual members. For example:

class Parent {
 var $ID;
 
 function __get($name){
  switch( $name ){
   case 'Child':
    $this->Child = new Child(); // return a child
  }
  return $this->$name;
 }
}

...will work! But there are some important drawbacks: your IDE's code completion will not provide the Parent->Child name as hint/tooltip, because it isn't declared anywhere in the code. The above code also won't know what instance to use (referred to by an ID in the database), because the Child field has to be unset for the getter method to be invoked.

Now (to make it short) there is a simple solution to make the virtual fields be known by the IDE and to make the code know what instance is referred to: remember and unset the field on creation! Just add a constructor like:

function __construct(){
 $this->_ref_Child = $this->Child; // remember the Child ID
 unset( $this->Child ); // unset Child, required for the __get() to be called
}

modify the __get() like this:

function __get($name){
 switch( $name ){
  case 'Child':
   $this->Child = new Child( $this->_ref_Child ); // instantiate the Child
   break;
 }
 return $this->$name; // return the requested member
}

Well that's all... nearly all, but the rest is easy and just requires some development. Don't forget to consider the following:
- What happens on serialize()/unserialize() of your proxy implementing objects?
- See other magic methods: __sleep(), __wakeup()!
- What happens when saving your proxied object to a database?
- See (for example) __toString(), as this could convert your objects to an ID for you on demand!

That's all for now. Hope this little study trip through a proxy pattern implementation took you a little further! Consider telling others about trash-factor.com, and drop a comment to tell me if you like it.