在没有组合的情况下解决 PHP 中的多重继承

Solving multiple inheritance in PHP without composition

我正在使用 Yii2 和 PHP 开发一个网络应用程序,我面临着典型的多重继承情况。

我有 classes AB 扩展 Yii2 的 ActiveRecord class 因为它们代表存储在数据库中的关系数据。但是后来我有了 class C,它不(也不应该)扩展 ActiveRecord 但与 AB 共享共同的行为和成员变量。换句话说,三个 class 确实与 real-world 实体共享一个共同的 "is a" 关系,但只有 AB 可存储在数据库中。

到目前为止,我的工作方式是使用 traits :

abstract class AbstractMotherClass extends ActiveRecord {
    use MyTrait;
}

class A extends AbstractMotherClass {}

class B extends AbstractMotherClass {}

class C {
    use MyTrait;
}

trait MyTrait {
    public $someVariableInherentToAllThreeClasses;

    public function someMethodInherentToAllThreeClasses() {
        // do something
    }
}

然后我有一个方法可以采用三个 class 中的任何一个(ABC)并使用它。直到现在,我只需要向它扔 AB 所以我只写了

public fonction someMethod(AbstractMotherClass $entity) {}

所以我可以在 IDE 中获得类型提示和其他东西。但是现在我也必须传递 C 并且应用程序崩溃,因为如果我调用 someMethod(new C());,该方法没有获得其预期的 AbstractMotherClass 实例。为了解决这个问题,我需要一个通用的 class,所有 ABC 都可以扩展,这样我就可以在 class 中键入提示我的方法。但这将是多重继承,因为 AB 也必须扩展 ActiveRecordC 不能。

我发现了很多多重继承问题,但它们都已通过更改 object 结构、拆分职责、使用组合而不是继承等方式解决。我无法在这里应用这些解决方案,因为它们看起来既不合适也不实用,但我可能是错的。

最好的方法是什么?

另外如果谁有更好的标题建议,我很乐意更改(我找不到好的标题)。

正如 Greg Schmidt 所提到的,您可以使用接口

class ActiveRecord {

}

interface SameInterface {
    public function someMethodInherentToAllThreeClasses();
}

abstract class AbstractMotherClass extends ActiveRecord implements SameInterface{
    use MyTrait;
}

class A extends AbstractMotherClass {}

class B extends AbstractMotherClass {}

class C implements SameInterface{
    use MyTrait;
}

trait MyTrait {
    public $someVariableInherentToAllThreeClasses;

    public function someMethodInherentToAllThreeClasses() {
        return 'bar';
    }
}

function foo(SameInterface $o) {
    return $o->someMethodInherentToAllThreeClasses().PHP_EOL;
}

echo foo(new C());

当然,您必须在界面中复制粘贴 someMethodInherentToAllThreeClasses。接口通常用于解决一些多重继承问题。