带接口的PHP多重继承

时间:2012-12-20 05:48:08

标签: php oop inheritance interface

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

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的新类,并将相同的代码复制到新类中。

我有什么遗失的吗?

5 个答案:

答案 0 :(得分:27)

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

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() { }
}

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

答案 1 :(得分:21)

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

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

客户端代码本质上是数据请求序列中的“最后一步”。 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对象以外的任何内容,
  3. showProfile()将失败。
  4. 1很容易通过抽象类和方法(或通过接口)来解决。 2起初听起来也很简单,因为你可以让Moderator,Admins和Members成为User基类的所有子类。

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

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

    所以现在你有点卡住了。 showProfile()需要能够接受的不仅仅是User对象。实际上,您不知道最终想要传递的对象类型。但与此同时,由于你总是希望能够获取$ 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()。

    一种人为的例子,但至少应该说明接口的概念。

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

答案 2 :(得分:3)

只有Interfaces才能进行多重继承!

比如我的输出:

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接口扩展了它们。
  • 我们有D类实现C接口
  • 之后
  • 最后,我问$ d对象是否是A接口的实例,是的,这是真的

对于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

答案 3 :(得分:1)

与许多OOP支持的语言一样,PHP中无法实现多重继承

请参阅类似主题here。该主题位于AS3,但会给您答案。

在同一篇文章here

中回答了特别关于使用接口求解的问题

希望这有帮助

答案 4 :(得分:0)

正如@tonicospinelli告诉here,似乎确实,PHP允许接口的多重继承,但它没有明确解释,只是given an example < / p>

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

声明 Class 实现&#34;多接口&#34; (1),您可以使用已经定义的 Traits 来确保继承良好。

  

(1):说&#34;多界面&#34;我的意思是实现从多个其他接口扩展的接口的类