PHP Multiple Inheritance with Interfaces

后端 未结 5 1255
醉话见心
醉话见心 2020-12-14 19:39

I\'m trying to understand how using interfaces gives me multiple inheritance as I\'ve been googling.

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


        
相关标签:
5条回答
  • 2020-12-14 19:41

    The first thing to understand about interfaces is that they are NOT used for inheritance. That is a very important thing to understand. If you're trying to make several classes share the same concrete code, that is not what an interface is for.

    The second thing to understand is the difference between client code, and service code.

    Client code is essentially the "last step" in a sequence of requests for data. A controller or a view in MVC can be considered client code. The model, meanwhile can be considered service code.

    Interfaces are intended for client code to enforce consistency in the types of data it gets from services. Or another way to think about it - interfaces are a way for services to make sure they will be compatible with a request from client code. That is ALL they do. They quite literally provide an interface by which data is accessed, not an implementation that multiple classes can share.

    So to give you a concrete example:

    Client Code - a ProfileViewController class for a user's forum profile

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

    Service Code - a User model that retrieves data and passes it on to the client code that is requesting it

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

    Now suppose later on you decide to break up Users into Members, Administrators, Referees, Moderators, Writers, Editors etc, and that each has their own unique type of profile. (e.g. its own custom query, or data, or what have you)

    There are now two problems present here:

    1. You need to guarantee that whatever you pass in there will contain a getProfile() method.
    2. showProfile() will fail if you pass in anything other than a User object.

    1 is easy to solve through abstract classes and methods (or through Interfaces). 2 at first sounds easy as well, because you can just make Moderators, Admins, and Members all subclasses of a User base class.

    But then what happens when down the road, in addition to USER profiles, you want to have generic profiles for things. Perhaps you want to show profiles of sports players, or even profiles of celebrities. They're not users, but they still have profiles/details pages.

    Because they're not users, it may not make any sense to consider them subclasses of User.

    So now you're a bit stuck. showProfile() needs to be able to accept more than just a User object. In fact, you don't know what type of object you will ultimately want to pass in there. But at the same time, since you always want to be able to grab $user->getProfile(), anything you pass in there must be generic enough to be passed in, AND implement a concrete getProfile() method.

    Solution? Interfaces!!!!!

    First some service code

    // 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;
        }
    }
    

    Next, the client code that will use it

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

    And there you have it. showProfile() has now been abstracted enough that it doesn't care what object it gets, it only cares that the object has a public getProfile() method. So now you can create new types of objects to your heart's content, and if they are intended to have profiles, you can just give them "implements IHasProfile" and they will automatically just work with showProfile().

    Kind of a contrived example, but it should illustrate at least the concept of interfaces.

    Of course, you could just be "lazy" and not typecast the object at all, and thus allowing ANY object to be passed in. But that's a separate topic entirely ;)

    0 讨论(0)
  • 2020-12-14 19:45

    Multiple inheritance is possible only for Interfaces!

    such as my output for it:

    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
    
    • I created A and B interfaces and C interface extends them.
    • After we have D class which implements C interface
    • Finally, I ask if $d object is instanceof A interface, yeah it's true

    For the lulz, I try to create E class which extends D and stdclass classes and get error!

    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
    
    0 讨论(0)
  • 2020-12-14 19:50

    PHP doesn't have multiple inheritance. If you have PHP 5.4, though, you can use traits to at least avoid every class having to copy code.

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

    Note, though, you have to both implement the interface and use the trait (or, of course, provide your own implementation). And C and D are not related at all, except in both implementing the A interface. Traits are basically just interpreter-level copy and paste, and do not affect inheritance.

    0 讨论(0)
  • 2020-12-14 19:57

    Multiple inheritance is not possible in PHP like in many OOP supported languages

    See similar topic here. The topic is in AS3 but gives you answer.

    To answer particularly about solving using interfaces is answered in the same post here

    Hope this helps

    0 讨论(0)
  • 2020-12-14 20:01

    As told here by @tonicospinelli, it seems that indeed, PHP allows multiple inheritance of interfaces, but it isn't clearly explained, just given an example

    The way multiple inheritance works, PHP passes these using Traits that implement Interfaces.

    Once you declare a Class implementing a "multi-interface" (1), you may use already defined Traits to assure inheritance is well-performed.

    (1): Saying "multi-interface" I mean a class implementing an interface what extends from multiple other interfaces

    0 讨论(0)
提交回复
热议问题