37

Why we are not allowed to extend Traits with Classes in PHP?

For example:

Trait T { }

Class C use T {}
/* or */
Class C extends T {}

Is there any potential conflict for such syntax? I do not think so.

andrewtweber
  • 24,520
  • 22
  • 88
  • 110
Meglio
  • 1,646
  • 2
  • 17
  • 33

3 Answers3

45

The PHP manual states thus:

Traits is a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way which reduces complexity, and avoids the typical problems associated with multiple inheritance and Mixins.

If you're looking to extend a trait, then it should probably be a class. If you have a set of methods in one class that you want to use in others, but it feels inappropriate to extend the class (eg. class Animal extends Vehicle), then in PHP 5.4 it could work well as a trait.

To answer the question more directly, you don't 'extend' a trait, but you can create traits which themselves use other traits. As per the PHP manual:

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

You can consider this to be a way to maintain your traits in logical groups, and to introduce some modularity.

Edit: having seen some of the comments, I think it's worthwhile to note that using a trait in a base class also means that trait is in any class that extends it, and the trait's functions take precedence over the base class'. Putting it in the child class would merely make the trait's functions unavailable to the parent/base class.

Parent > Trait > Child

http://php.net/manual/en/language.oop5.traits.php

leemeichin
  • 3,339
  • 1
  • 24
  • 31
36

You can extend traits somewhat. Expanding on mrlee's answer, when you use a trait you can rename its methods.

Say for example you have a "parent" trait that was defined by your framework:

trait FrameworkTrait {
    public function keepMe() {
        // Framework's logic that you want to keep
    }

    public function replaceMe() {
        // Framework's logic that you need to overwrite
    }
}

Simply pull in the parent trait, rename its replaceMe method to something else, and define your own replaceMe method.

trait MyTrait {
    use FrameworkTrait {
        FrameworkTrait::replaceMe as frameworkReplaceMe;
    }

    public function replaceMe() {
        // You can even call the "parent" method if you'd like:
        $this->frameworkReplaceMe();

        // Your logic here
    }
}

And then in your class:

class MyClass {
    use MyTrait;
}

Now objects of this class can do this:

$obj = new MyClass();
    
$obj->keepMe();             // calls "parent" trait
$obj->replaceMe();          // calls "child" trait
$obj->frameworkReplaceMe(); // calls "parent" trait
andrewtweber
  • 24,520
  • 22
  • 88
  • 110
8

Only classes can be extended. Traits are not classes. They can be used/included by classes but are not classes themselves. If you think a trait needs to be extended then it probably should be a class, probably an abstract one, and not a trait.

John Conde
  • 217,595
  • 99
  • 455
  • 496
  • The idea here is for shorter syntax, not for the way to actually extend traits. – Meglio Apr 07 '12 at 17:38
  • 3
    @Meglio: syntax has no length, so there is no shorter syntax. – hakre Apr 07 '12 at 17:39
  • 4
    But what to do if I have some 3rd party framework (Laravel, to be more exact) and I need one of its traits, but with a small fix for one function which is marked as `protected` in the trait? I don't want to change Laravel code, so it would be great to have some way to override this protected method in my own trait. To be even more specific, the problem is with a hard coded text string which I want to localize. – JustAMartin Apr 10 '15 at 12:03
  • @JustAMartin see my answer – andrewtweber Jun 07 '16 at 19:01
  • You're partially wrong. Interfaces can be extended too. – xZero Mar 06 '19 at 16:11