Multiple inheritance with PHP and Traits


Multiple inheritance isn’t allowed in PHP. With Python we can do things like that:

class ClassName(Base1, Base2):
    ....

That’s no possible with PHP (in Java is not possible either), but today we can do something similar (is not the exactly the same) with Traits. Let me explain that: Instead of classes we can create Traits:

<?php
trait Base1
{
    public function hello1($name)
    {
        return "Hello1 {$name}";
    }
} 

trait Base2
{
    public function hello2($name)
    {
        return "Hello2 {$name}";
    }
} 

And now we can use those traits (instead of to extend multiple classes)

<?php
class ClassName
{
    use Base1, Base2;
} 

The main reason because multiple inheritance isn’t allowed in PHP, Java and another languages is is due to the collisions. If we extends from two classes with the same method, which is the good one?
Python solves this problem with a easy solution: The first one is the good one:

class Base1:
    def hello1(self, name):
        return "Hello1 " + name

class Base2:
    def hello1(self, name):
        return "Hello2 " + name

class ClassName(Base1, Base2):
    pass
c = ClassName()
print c.hello1("Gonzalo")

Will output “Hello1 Gonzalo” but if change the inheritance order to:

class ClassName(Base2, Base1):
    pass

The output will be “Hello2 Gonzalo”

Traits in PHP doesn’t solve the problem “out of the box”. If we use the following script:

<?php
trait Base1
{
    public function hello1($name)
    {
        return "Hello1 {$name}";
    }
}

trait Base2
{
    public function hello1($name)
    {
        return "Hello2 {$name}";
    }
}

class ClassName
{
    use Base1, Base2;
}

$class = new ClassName();
echo $class->hello1("Gonzalo");

Our script will throw a Fatal error:

PHP Fatal error: Trait method hello1 has not been applied, because there are collisions with other trait methods on ClassName on line 23

If we want to avoid collisions, we need to describe explicitly what function we will use. It’s not difficult:

<?php
trait Base1
{
    public function hello1($name)
    {
        return "Hello1 {$name}";
    }
}

trait Base2
{
    public function hello1($name)
    {
        return "Hello2 {$name}";
    }
}

class ClassName
{
    use Base1, Base2 {
        Base1::hello1 insteadof Base2;
    }
}

$class = new ClassName();
echo $class->hello1("Gonzalo");
About these ads

About Gonzalo Ayuso

Web Architect specialized in Open Source technologies. PHP, Python, JQuery, Dojo, PostgreSQL, CouchDB and node.js but always learning.

Posted on December 17, 2012, in php, Technology and tagged , , . Bookmark the permalink. 8 Comments.

  1. Perl did the same thing for MI, left first resolution of inherited methods. A simple approach that I rather like.

  2. Yeah, it gets a little annoying writing, what should be, redundant code.

    What is the reason(s) a trait collision is resolved in this way and not like, for example, the python way?

  3. May be because the PHP’s implementation is more flexible?
    What will be if you have several methods with the same name and you should call some from trait1 and other from trait2

  4. “The main reason because multiple inheritance isn’t allowed in PHP, Java and another languages is is due to the collisions.”

    .. or maybe because its an inherently bad idea..

    • inheritance or multiple inheritance? IMHO multiple inheritance is as good/bad as single inheritance. If you are saying single inherently is a bad idea I’m not 100% percent agree with you. But I must admit that with inheritance is very easy to violate a couple of SOLID values. Abstract classes has a trend to become ugly container of incoherent functions. In one code retreat someone said “inheritance is for losers”. Maybe he’s right :)

  1. Pingback: Лучшее в мире PHP за 2012 и дайджест интересных материалов за последние две недели №7 (15.12.2012 — 28.12.2012) | NEWS.ptaah.org.ua

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 963 other followers

%d bloggers like this: