在没有组合的情况下解决 PHP 中的多重继承
Solving multiple inheritance in PHP without composition
我正在使用 Yii2 和 PHP 开发一个网络应用程序,我面临着典型的多重继承情况。
我有 classes A
和 B
扩展 Yii2 的 ActiveRecord
class 因为它们代表存储在数据库中的关系数据。但是后来我有了 class C,它不(也不应该)扩展 ActiveRecord
但与 A
和 B
共享共同的行为和成员变量。换句话说,三个 class 确实与 real-world 实体共享一个共同的 "is a" 关系,但只有 A
和 B
可存储在数据库中。
到目前为止,我的工作方式是使用 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 中的任何一个(A
、B
或 C
)并使用它。直到现在,我只需要向它扔 A
或 B
所以我只写了
public fonction someMethod(AbstractMotherClass $entity) {}
所以我可以在 IDE 中获得类型提示和其他东西。但是现在我也必须传递 C
并且应用程序崩溃,因为如果我调用 someMethod(new C());
,该方法没有获得其预期的 AbstractMotherClass
实例。为了解决这个问题,我需要一个通用的 class,所有 A
、B
和 C
都可以扩展,这样我就可以在 class 中键入提示我的方法。但这将是多重继承,因为 A
和 B
也必须扩展 ActiveRecord
但 C
不能。
我发现了很多多重继承问题,但它们都已通过更改 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。接口通常用于解决一些多重继承问题。
我正在使用 Yii2 和 PHP 开发一个网络应用程序,我面临着典型的多重继承情况。
我有 classes A
和 B
扩展 Yii2 的 ActiveRecord
class 因为它们代表存储在数据库中的关系数据。但是后来我有了 class C,它不(也不应该)扩展 ActiveRecord
但与 A
和 B
共享共同的行为和成员变量。换句话说,三个 class 确实与 real-world 实体共享一个共同的 "is a" 关系,但只有 A
和 B
可存储在数据库中。
到目前为止,我的工作方式是使用 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 中的任何一个(A
、B
或 C
)并使用它。直到现在,我只需要向它扔 A
或 B
所以我只写了
public fonction someMethod(AbstractMotherClass $entity) {}
所以我可以在 IDE 中获得类型提示和其他东西。但是现在我也必须传递 C
并且应用程序崩溃,因为如果我调用 someMethod(new C());
,该方法没有获得其预期的 AbstractMotherClass
实例。为了解决这个问题,我需要一个通用的 class,所有 A
、B
和 C
都可以扩展,这样我就可以在 class 中键入提示我的方法。但这将是多重继承,因为 A
和 B
也必须扩展 ActiveRecord
但 C
不能。
我发现了很多多重继承问题,但它们都已通过更改 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。接口通常用于解决一些多重继承问题。