16

我正在尝试了解使用接口如何为我提供多重继承,因为我一直在谷歌搜索。

class A
{
 function do1(){}
 function do2(){}
 function do3(){}
}

class B extends A
{
 function do4(){}
 function do5(){}
 function do6(){}
}

class C extends B
{
}

在上面的示例中,C 类具有 A 类和 B 类的所有方法。但是,B 类也具有 A 类的所有方法,这不是必需的。

我的搜索已经通过将方法移动到类并创建接口来使用接口来解决这个问题,如下所示。

interface A
{
     function do1();
     function do2();
     function do3();
}

interface B
{
     function do4();
     function do5();
     function do6();
}

class C implements A, B
{
     function do1(){}
     function do2(){}
     function do3(){}
     function do4(){}
     function do5(){}
     function do6(){}
}

我真的不明白这是如何解决问题的,因为所有代码都在新类中。如果我只想像原来一样使用 A 类,我将不得不创建一个实现接口 A 的新类并将相同的代码复制到新类。

有什么我想念的吗?

4

5 回答 5

28

PHP没有多重继承。但是,如果您有 PHP 5.4,则可以使用特征至少避免每个类都必须复制代码。

interface A {
    public function do1();
    public function do2();
    public function do3();
}

trait Alike {
    public function do1() { }
    public function do2() { }
    public function do3() { }
}


interface B {
    public function do4();
    public function do5();
    public function do6();
}

trait Blike {
    public function do4() { }
    public function do5() { }
    public function do6() { }
}


class C implements A, B {
    use Alike, Blike;
}

class D implements A {
    use Alike;

    // You can even "override" methods defined in a trait
    public function do2() { }
}

但是请注意,您必须同时实现接口并使用特征(或者,当然,提供您自己的实现)。和 C 和 D 完全没有关系,除了都实现了 A 接口。Traits 基本上只是解释器级别的复制和粘贴,不影响继承。

于 2012-12-20T05:56:06.797 回答
23

首先要了解接口是它们不用于继承。理解这一点非常重要。如果您试图让多个类共享相同的具体代码,那不是接口的用途。

第二件要了解的是客户端代码和服务代码之间的区别。

客户端代码本质上是一系列数据请求中的“最后一步”。MVC 中的控制器或视图可以视为客户端代码。该模型同时可以被认为是服务代码。

接口旨在供客户端代码强制其从服务获取的数据类型的一致性。或者另一种思考方式——接口是服务确保它们与来自客户端代码的请求兼容的一种方式。这就是他们所做的一切。它们确实提供了一个访问数据的接口,而不是多个类可以共享的实现。

所以给你一个具体的例子:

客户端代码 - 用户论坛个人资料的 ProfileViewController 类

class ProfileViewController
{
    public function showProfile(User $user)
    {
         $user->getProfile();
    }
}

服务代码 - 一种用户模型,用于检索数据并将其传递给请求它的客户端代码

class User
{
    public function getProfile()
    {
         $profile = Do some SQL query here or something
         return $profile;
    }
}

现在假设稍后您决定将用户分为成员、管理员、推荐人、版主、作家、编辑等,并且每个人都有自己独特的个人资料类型。(例如它自己的自定义查询,或数据,或你有什么)

现在这里存在两个问题:

  1. 您需要保证您传入的任何内容都将包含 getProfile() 方法。
  2. 如果您传入 User 对象以外的任何内容,showProfile() 将失败。

1 通过抽象类和方法(或通过接口)很容易解决。2 起初听起来也很简单,因为您可以将 Moderators、Admins 和 Members 设为 User 基类的所有子类。

但是接下来会发生什么,除了用户配置文件之外,您还希望拥有通用配置文件。也许您想显示体育运动员的个人资料,甚至名人的个人资料。他们不是用户,但他们仍然有个人资料/详细信息页面。

因为他们不是用户,所以将他们视为 User 的子类可能没有任何意义。

所以现在你有点卡住了。showProfile() 需要能够接受的不仅仅是用户对象。实际上,您不知道最终要传入哪种类型的对象。但同时,由于您总是希望能够获取 $user->getProfile(),因此您传入的任何内容都必须足够通用才能传入,并实现具体的 getProfile() 方法。

解决方案?接口!!!!

首先是一些服务代码

// First define an interface for ANY service object that will have a profile

interface IHasProfile
{
    public function getProfile();
}


// Next, define the class for an object that should have a profile. I'll do a bunch for the sake of an example...

class User implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique user profile query here
         return $profile;
    }
}


class Celebrity implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique celebrity profile query here
         return $profile;
    }
}


class Car implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique vehicle profile query goes here
         return $profile;
    }
}

接下来,将使用它的客户端代码

class ProfileViewController
{
    public function showProfile(IHasProfile $obj)
    {
         $obj->getProfile();
    }
}

你有它。showProfile() 现在已经足够抽象,它不关心它得到什么对象,它只关心对象有一个公共的 getProfile() 方法。因此,现在您可以根据自己的意愿创建新类型的对象,如果它们打算具有配置文件,您可以只给它们“实现 IHasProfile”,它们将自动与 showProfile() 一起使用。

有点人为的例子,但它至少应该说明接口的概念。

当然,您可以只是“懒惰”并且根本不对对象进行类型转换,从而允许传入任何对象。但这完全是一个单独的主题;)

于 2013-07-20T00:02:32.180 回答
5

多重继承仅适用于接口!

比如我的输出:

php > interface A{};
php > interface B{};
php > interface C extends A,B{};
php > class D implements C{};
php > $d = new D();
php > echo ($d instanceof A);
1
  • 我创建了 A 和 B 接口,C 接口扩展了它们。
  • 在我们有了实现 C 接口的 D 类之后
  • 最后问一下$d对象是不是instanceof的接口,是啊是真的

对于 lulz,我尝试创建扩展 D 和 stdclass 类的 E 类并得到错误!

php > class E extends D, stdclass{};
PHP Parse error:  syntax error, unexpected ',', expecting '{' in php shell code on line 1

Parse error: syntax error, unexpected ',', expecting '{' in php shell code on line 1
于 2015-06-29T17:19:33.150 回答
1

OOP像许多受支持的语言一样,在 PHP 中不可能进行多重继承

在此处查看类似主题。主题在AS3但给你答案。

在这里的同一篇文章中回答了特别关于使用接口解决的问题

于 2012-12-20T05:54:55.910 回答
0

正如@tonicospinelli所说,似乎PHP确实允许接口的多重继承,但没有明确解释,只是给出了一个例子

多重继承的工作方式,PHP 使用实现Interfaces的Traits传递这些。

一旦您声明了一个实现“多接口”的类(1),您就可以使用已经定义的Traits来确保继承性能良好。

(1) : 说“多接口”我的意思是一个实现一个接口的类,它从多个其他接口扩展而来

于 2017-05-08T08:40:14.290 回答