Here's fun, an attempt to make some degree of multiple inheritance work in PHP using mixins. It's not particularly pretty, doesn't support method visibility modifiers and, if put to any meaningful purpose, could well make your call stack balloon to Ruby-on-Rails-esque proportions, but it does work.
protected$_mixMap= array();
public function__construct(){$this->_mixMap=$this->collectMixins($this);
}
public function__call($method,$args){// doesn't pass scope
//return call_user_func_array(array($className, $method), $args);
// Error: Given object is not an instance of the class this method was declared in
//$method = new ReflectionMethod($className, $method);
//return $method->invokeArgs($this, $args);$payload=$this->buildMixinPayload($this->_mixMap,$method,$args);
if(!$payload) throw newException('Method '.$method.' not found');
list($mixinMethod, list($method,$args)) =$payload;
return$this->$mixinMethod($method,$args);
}
protected functioncollectMixins($class){
static$found= array();
static$branch= array();
if(empty($branch))$branch[] =get_class($this);$mixins= array();
foreach(array_reverse(get_class_methods($class)) as$method){
if(preg_match('/^mixin(\w+)$/',$method,$matches)){$className=$matches[1];
if(in_array($className,$branch))
throw newException('Circular reference detected '.implode(' > ',$branch) .' > '.$className);
if(!in_array($className,$found)){
if(!class_exists($className)) throw newException('Class '.$className.' not found');// populate props from mixin classforeach(get_class_vars($className) as$key=>$value){
if(!property_exists($this,$key))$this->$key=$value;
}$found[] =$branch[] =$className;$mixins[$className] =$this->collectMixins($className);
}$branch= array(get_class($this));
}
}
return$mixins;
}
protected functionbuildMixinPayload($mixins,$method,$args){
foreach($mixinsas$className=>$parents){$mixinMethod='mixin'.$className;
if(method_exists($className,$method)) return array($mixinMethod, array($method,$args));
if(!empty($parents) &&$return=$this->buildMixinPayload($parents,$method,$args)){
return array($mixinMethod,$return);
}
}
returnfalse;
}
}?>