Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/230.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在PHP中解决无组合的多重继承_Php_Structure_Multiple Inheritance_Composition - Fatal编程技术网

在PHP中解决无组合的多重继承

在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

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

我有类
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,并使它们成为接口的一部分?好的,我同意并接受答案,谢谢!