PHP和多重继承;我知道你不能,但那我该怎么办?

时间:2011-11-05 16:50:41

标签: php oop dependencies multiple-inheritance composition

我理解PHP中根本不支持multiple inheritance 1 ,虽然存在许多“hacks”或变通方法来模拟它,但我也理解{{3}这样的方法可能比这些变通方法更灵活,更稳定,更易理解。奇怪的是,PHP的5.4 object composition将是合适的解决方案,但我们还没有,我们是不是。

现在,这不仅仅是一个“ amidoinitrite?”问题,但我想确保我的方法对其他人有意义。

鉴于我有课程ActionEvent还有更多,但我们会保持简短)并且他们都需要( near >)相同的方法,显而易见的方法是;创建一个共同的基类,扩展和去;毕竟,它们在概念上相似,足以构成一个阶级层次结构中的兄弟姐妹(我认为

问题是Event需要扩展一个本身无法扩展的类( Exception )。方法(和属性)都属于“属性”值,我们称之为“选项”和“数据”,其中“选项”是存储在类级别的值,“数据”是存储在实例级别的值。

除了(没有双关语Exception类之外,我可以简单地创建一个所有相关对象扩展的公共类,以便继承必要的功能,但我是想知道我能做些什么来避免Event中看似不可避免的代码重复;此外,其他在概念上与兄弟姐妹不相似的类需要此功能。

到目前为止,答案似乎是,使用对象组合方法,创建一个Data类,并在两点进行管理:

  • 在对象实例化时,创建一个与对象一起使用的Data实例作为“数据”。
  • 在某些时候(通过静态initialize()方法)创建一个Data实例,静态地将该类用作“选项”。

例如,名为IDataIOption的接口将由需要此功能的类实现。 IData只是在使用者身上强制执行Data类的实例方法,并且调用将转发到实例Data属性对象,而IOption将强制执行类似命名的方法( 将“data”替换为“option”),这些方法将转发给静态Data属性对象。

我正在看的是这样的事情(这些方法在外观上有些天真,但我为了简洁起见,我已经将它们缩小了):

interface IData{

    public function setData($name, $value);

    public function putData($name, &$variable);

    public function getData($name = null);

}

interface IOption{

    public static function initializeOptions();

    public static function setOption($name, $value);

    public static function setOptions(Array $options);

    public static function getOptions($name = null);

}

class Data implements IData{

    private $_values = array();

    public function setData($name, $value){
        $this->_values[$name] = $value;
    }

    public function putData($name, &$variable){
        $this->_values[$name] = &$variable;
    }

    public function getData($name = null){
        if(null === $name){
            return $this->_values;
        }
        if(isset($this->_values[$name])){
            return $this->_values[$name];
        }
        return null;
    }

}

class Test implements IData, IOption{

    private static $_option;
    private $_data;

    public static function initializeOptions(){
        self::$_option = new Data();
    }

    public static function setOption($name, $value){
        self::$_option->setData($name, $value);
    }

    public static function setOptions(Array $options){
        foreach($options as $name => $value){
            self::$_option->setData($name, $value);
        }
    }

    public static function getOptions($name = null){
        return self::$_option->getOptions($name);
    }

    public function __construct(){
        $this->_data = new Data();
    }

    public function setData($name, $value){
        $this->_data->setData($name, $value);
        return $this;
    }

    public function putData($name, &$variable){
        $this->_data->putData($name, $variable);
        return $this;
    }

    public function getData($name = null){
        return $this->_data->getData($name);
    }

}

那么我从哪里开始呢?我无法摆脱这种感觉,即我正在摆脱优秀的设计;我在客户端类和存储类之间引入了不可逆的依赖关系,接口无法明确强制执行。


修改:或者,我可以将Data必要时)的引用保持公开,从而无需代理方法,从而简化了构图。那么问题是,我不能偏离Data类功能,例如,如果我需要递归地getData()行动,就像这个片段举例说明的那样:

function getData($name = null){
    if(null === $name){
        // $parent_object would refer to $this->_parent
        // in the Test class, given it had a hierarchal
        // implementation
        return array_replace($parent_object->getData(), $this->_values);
    }
    // ...
}

当然,这一切都归结为每个类别的定义,以支持任何偏离默认实现。

我认为最终的结果是,我无法理解代码重复的位置“好”(或更准确,不可避免)以及我可以将常用功能提取到容器中的位置,以及如何跨类引用和使用包含的功能,在必要时偏离(通常可忽略)。同样,特征(我在测试中的粗略测试)似乎是完美的契合,但组合原则早在​​5.4之前就存在了(和PHP完全就此而言并且我确信有一种“经典”的方法来实现这一目标。


<子> 1.有趣的是,维基百科的traits页面已被标记为进行版权调查。钻石问题似乎是一个合适的替代品。

1 个答案:

答案 0 :(得分:1)

编辑:我刚刚再次阅读了您的问题,您似乎在暗示您实际上是在使用getter和setter来操纵数据。如果是这种情况,那么您可以向我提供有关您正在尝试实现的内容的更多详细信息。我怀疑你是如何决定对对象和数据进行建模的,这导致你遇到这种情况,另一种方法可以解决问题。

您不需要多重继承。你甚至不需要你编写的大部分代码。

如果类'Data'和'Option'的目的是简单地存储数据,那么使用数组。或者,如果您更喜欢对象的语法,则将数组转换为对象或stdClass的实例:

$person = (object)array(
    'name' => 'Peter',
    'gender' => 'Male'
);

OR

$person = new stdClass;
$person->name = 'Peter';
$person->gender = 'Male';

拥有一大堆实际上并没有对数据做任何事情的getter和setter是毫无意义的。