Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Multiple Inheritance with Interfaces

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

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

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

class C extends B
{
}

In the above example, class C has all the methods from class A and B. However, class B also has all the methods of class A, which is not necessary desired.

My searches have come up to use interfaces to solve this issue by moving methods to a class and creating interfaces, as below.

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

I don't really see how this solves the issue because all the code is in the new class. If I just wanted to use class A as originally, I would have to create a new class that implement interface A and copy the same code to the new class.

Is there something I'm missing?

like image 386
tdbui22 Avatar asked Dec 20 '12 05:12

tdbui22


People also ask

Does multiple inheritance apply to interfaces?

Java allows multiple inheritance using interfaces. Interfaces could only define abstract methods, that is, methods without any implementation. So if a class implemented multiple interfaces with the same method signature, it was not a problem.

Can I implement multiple interfaces in PHP?

Classes may implement more than one interface if desired by separating each interface with a comma. A class can implement two interfaces which define a method with the same name, only if the method declaration in both interfaces is identical.

Why is multiple inheritance not supported in PHP?

PHP programming language doesn't even support the multiple inheritance/inheritances. PHP supports multiple inheritances only by using interfaces or Traits in PHP instead of classes so that we can implement it. Traits are a type of class that enables multiple case classes, objects, classes, and traits.

Can interface extend multiple interfaces in PHP?

Extending multiple interfaces is allowed. It just fails if the same method is declared in two or more of them.


2 Answers

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.

like image 50
cHao Avatar answered Sep 23 '22 05:09

cHao


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 ;)

like image 22
AgmLauncher Avatar answered Sep 20 '22 05:09

AgmLauncher