在PHP中解决无组合的多重继承
我正在使用Yii2和PHP开发一个web应用程序,面临着典型的多重继承情况 我有类在PHP中解决无组合的多重继承,php,structure,multiple-inheritance,composition,Php,Structure,Multiple Inheritance,Composition,我正在使用Yii2和PHP开发一个web应用程序,面临着典型的多重继承情况 我有类A和B扩展了Yii2的ActiveRecord类,因为它们表示存储在数据库中的关系数据。但是我有C类,它不(也不应该)扩展ActiveRecord,而是与A和B共享公共行为和成员变量。换句话说,这三个类与现实世界实体真正共享一个共同的“is a”关系,但只有a和B可存储在数据库中 到目前为止,我的工作方式是通过使用特征: abstract class AbstractMotherClass extends Acti
A
和B
扩展了Yii2的ActiveRecord
类,因为它们表示存储在数据库中的关系数据。但是我有C类,它不(也不应该)扩展ActiveRecord
,而是与A
和B
共享公共行为和成员变量。换句话说,这三个类与现实世界实体真正共享一个共同的“is a”关系,但只有a
和B
可存储在数据库中
到目前为止,我的工作方式是通过使用特征:
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
}
}
然后我有了一个方法,它可以接受三个类(a
,B
或C
)中的任何一个,并使用它。到现在为止,我只需要向它抛出A
或B
,所以我就写了
public fonction someMethod(AbstractMotherClass $entity) {}
这样我就可以在IDE中得到类型提示和其他东西。但是现在我也必须通过C
,应用程序崩溃了,因为如果我调用someMethod(new C()),该方法没有得到预期的AbstractMotherClass
实例代码>。为了解决这个问题,我需要一个公共类,所有a
、B
和C
都可以扩展,这样我就可以在方法中键入hint类。但这将是多重继承,因为A
和B
也必须扩展ActiveRecord
,但C
不能
我发现了很多多重继承问题,但它们都通过改变对象结构、划分责任、使用组合而不是继承等方式得到了解决。我无法在这里应用这些解决方案,因为它们看起来既不合适也不实用,但我可能错了
最好的方法是什么
另外,如果有人有更好的标题建议,我很乐意更改它(我找不到一个好的)。正如格雷格·施密特(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());
当然,您必须复制粘贴接口中所有三个类中的某个方法。接口通常用于解决某些多重继承问题。正如格雷格·施密特(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());
当然,您必须复制粘贴接口中所有三个类中的某个方法。接口通常用于解决一些多重继承问题。您能定义一个MyTrait实现的接口,然后someMethod
可以接受这种类型的对象吗?我非常确定。但也许我不太理解你的评论,你的意思是下面的@zzarbi。你能定义一个MyTrait实现的接口,然后someMethod
可以接受这种类型的对象吗?我很确定。但也许我不太理解你的评论,你的意思是下面的@zzarbi。这确实是我想要的。谢谢你提供了详细的例子。但是,我相信这不会让我自动完成Trait中定义的公共变量,是吗?这可能没什么大不了的,但我认为这显示了一个设计问题,因为即使是IDE也无法确定正在使用什么。当我想使用它时,我不仅必须回到Trait来检查变量的确切语法,而且如果我以后想通过重构工具重命名它,我将遇到问题,因为IDE将无法在foo
方法中重命名调用。更正它不会给你变量自动完成。但是这个变量必须是公共的吗?它是一个在另一个类中计算的变量,因为它不是真正的类(a
,B
或C
)作业,然后在实例中设置,然后从其他地方读取。因此,如果我不将变量设置为public,我想我可以编写访问器,但如果我所做的只是读写变量,我看不出有什么意义。也许这里还有另一个设计问题,但我不这么认为,我认为有一种方法可以实现我所需要的,同时保持变量的公共性。@Scentle5S然后为该属性创建setter和getter,并使它们成为接口的一部分?好的,我同意并接受答案,谢谢!这确实可以满足我的大部分需求。谢谢你提供了详细的例子。但是,我相信这不会让我自动完成Trait中定义的公共变量,是吗?这可能没什么大不了的,但我认为这显示了一个设计问题,因为即使是IDE也无法确定正在使用什么。当我想使用它时,我不仅必须回到Trait来检查变量的确切语法,而且如果我以后想通过重构工具重命名它,我将遇到问题,因为IDE将无法在foo
方法中重命名调用。更正它不会给你变量自动完成。但是这个变量必须是公共的吗?它是一个在另一个类中计算的变量,因为它不是真正的类(a
,B
或C
)作业,然后在实例中设置,然后从其他地方读取。因此,如果我不将变量设置为public,我想我可以编写访问器,但如果我所做的只是读写变量,我看不出有什么意义。也许这里还有另一个设计问题,但我不这么认为,我认为有一种方法可以实现我所需要的,同时保持变量的公共性。@Scentle5S然后为该属性创建setter和getter,并使它们成为接口的一部分?好的,我同意并接受答案,谢谢!