Reputation: 2938
I'm trying to solve a design puzzle in the most efficient way, but I tend to end thinking that I really need a multiple inheritance here. So, here I am, asking the pros. I'm creating an active-record lib that will perform almost identical actions with different name
and value
variables. I'm on PHP 5.2.13
Suppose I have these classes:
class Property {
protected $_props = array();
function set($name, $value) {
$this->_props[$name] = $value;
};
}
class ColorProperties extends Property {
function red($value) {
$this->set('red', $value);
}
function blue($value) {
$this->set('blue', $value);
}
}
class LayoutProperties extends Property {
function x($value) {
$this->set('x', $value);
}
function y($value) {
$this->set('y', $value);
}
}
Now I need to create a class ShapeProperties
that will inherit from both, ColorProperties
and LayoutProperties
. So that:
$shape = new ShapeProperties();
$shape->x(10);
$shape->red(255);
The reason why I need it that way, is to have auto-completion in IDE with huge PHPDoc comment block for each property. So, seems that I'm leaning towards copy/paste out of despair.
I've got these classes (blocks):
class Red {
function red();
}
class LightRed {
function light_red();
}
class Blue {
function blue();
}
class LightBlue {
function light_blue();
}
class Green {
function green();
}
class LightGreen {
function light_green();
}
And now I need to build a numerous amount of classes using these blocks, ie:
class RGB extends Red, Green, Blue {
function red();
function blue();
function green();
}
class RLRB extends Red, LightRed, Blue {
function red();
function light_red();
function blue();
}
So if I switch word class with interface, I'll get what I need, but I need working implementation without loads of boilerplate code. Is there a way/approach to work this around in PHP?
Upvotes: 1
Views: 302
Reputation: 5431
You can use magic functions and delegation to do something similar. I hope your real case is not really about colors, because this would be a bit overkill to avoid a few one line functions.
You can provide an arbitrary list of implementations and cycle through them until you find one that has the appropriate method name. Call it with all of the arguments. There can be method clashes, just like it happens with multiple inheritance, except that here, no compiler will tell you. You also lose the argument validation and such.
class Color
{
private $implementations;
function __construct($implementations)
{
$this->implementations = $implementations;
}
function __call($functionName, $args)
{
foreach ($this->implementations as $impl) {
$callback = array($impl, $functionName);
if (is_callable($callback)) {
return call_user_func_array($callback, $args);
}
}
throw new Exception("Method not found: $functionName");
}
}
class RGB
{
function __construct()
{
parent::__construct(array(
new Red,
new Green,
new Blue,
));
}
}
$color = new RGB;
$color->red();
Upvotes: 2
Reputation: 29462
In the near future it will be possible with php 5.4 new feature - traits
. This will look like this:
trait RED{
function red(){ };
}
trait BLUE{
function blue(){ };
}
trait GREEN{
function green(){ };
}
class RGB{
use RED,GREEN,BLUE;
}
But for now, the best method seems to be using static methods and dependency injections, like this:
class RED{
static function get_red($obj){
return '0x'.dechex($obj->red);
}
}
class RGB{
public $red;
public $green;
public $blue;
public function __construct($r,$g,$b){
$this->red = $r;
$this->green = $g;
$this->blue = $b;
}
public function get_red(){
return RED::get_red($this);
}
}
$rgb = new RGB(255,255,255);
echo $rgb->get_red();
but you still have to declare all functions and make it call method from other class.
Upvotes: 1