394

I've been trying to study up on PHP lately, and I find myself getting hung up on traits. I understand the concept of horizontal code reuse and not wanting to necessarily inherit from an abstract class. What I don't understand is: What is the crucial difference between using traits versus interfaces?

I've tried searching for a decent blog post or article explaining when to use one or the other, but the examples I've found so far seem so similar as to be identical.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
datguywhowanders
  • 4,341
  • 6
  • 20
  • 14
  • 6
    interface do not have any code in the function bodies. they actually do not have any function bodies. – hakre Aug 16 '12 at 18:37
  • 3
    Despite my much-upvoted answer, I'd like it stated for the record that I'm generally **anti-trait/mixin**. Check this chat transcript to read [how traits often undermine solid OOP practices](http://chat.stackoverflow.com/transcript/message/4602577#4602577). –  Dec 01 '12 at 07:11
  • 2
    I'd argue to the contrary. Having worked with PHP for years before and since the advent of traits, I think it's easy to prove their worth. Just read through [this practical example](https://quickshiftin.com/blog/2014/11/php-traits) which enables 'image models' to also walk and talk like `Imagick` objects, less all the bloat needed in the old days before traits. – quickshiftin Nov 30 '14 at 00:53
  • 1
    Traits and interface are similar. The main difference is that the Traits allows you to implement the methods, the Interface don't. – John Nov 04 '18 at 22:28
  • interface is like requirement, trait is like addon. btw java, kotlin and rust merged traits and interfaces into one thing – quant2016 Feb 14 '23 at 19:01

13 Answers13

600

Public Service Announcement:

I want to state for the record that I believe traits are almost always a code smell and should be avoided in favor of composition. It's my opinion that single inheritance is frequently abused to the point of being an anti-pattern and multiple inheritance only compounds this problem. You'll be much better served in most cases by favoring composition over inheritance (be it single or multiple). If you're still interested in traits and their relationship to interfaces, read on ...


Let's start by saying this:

Object-Oriented Programming (OOP) can be a difficult paradigm to grasp. Just because you're using classes doesn't mean your code is Object-Oriented (OO).

To write OO code you need to understand that OOP is really about the capabilities of your objects. You've got to think about classes in terms of what they can do instead of what they actually do. This is in stark contrast to traditional procedural programming where the focus is on making a bit of code "do something."

If OOP code is about planning and design, an interface is the blueprint and an object is the fully constructed house. Meanwhile, traits are simply a way to help build the house laid out by the blueprint (the interface).

Interfaces

So, why should we use interfaces? Quite simply, interfaces make our code less brittle. If you doubt this statement, ask anyone who's been forced to maintain legacy code that wasn't written against interfaces.

The interface is a contract between the programmer and his/her code. The interface says, "As long as you play by my rules you can implement me however you like and I promise I won't break your other code."

So as an example, consider a real-world scenario (no cars or widgets):

You want to implement a caching system for a web application to cut down on server load

You start out by writing a class to cache request responses using APC:

class ApcCacher
{
  public function fetch($key) {
    return apc_fetch($key);
  }
  public function store($key, $data) {
    return apc_store($key, $data);
  }
  public function delete($key) {
    return apc_delete($key);
  }
}

Then, in your HTTP response object, you check for a cache hit before doing all the work to generate the actual response:

class Controller
{
  protected $req;
  protected $resp;
  protected $cacher;

  public function __construct(Request $req, Response $resp, ApcCacher $cacher=NULL) {
    $this->req    = $req;
    $this->resp   = $resp;
    $this->cacher = $cacher;

    $this->buildResponse();
  }

  public function buildResponse() {
    if (NULL !== $this->cacher && $response = $this->cacher->fetch($this->req->uri()) {
      $this->resp = $response;
    } else {
      // Build the response manually
    }
  }

  public function getResponse() {
    return $this->resp;
  }
}

This approach works great. But maybe a few weeks later you decide you want to use a file-based cache system instead of APC. Now you have to change your controller code because you've programmed your controller to work with the functionality of the ApcCacher class rather than to an interface that expresses the capabilities of the ApcCacher class. Let's say instead of the above you had made the Controller class reliant on a CacherInterface instead of the concrete ApcCacher like so:

// Your controller's constructor using the interface as a dependency
public function __construct(Request $req, Response $resp, CacherInterface $cacher=NULL)

To go along with that you define your interface like so:

interface CacherInterface
{
  public function fetch($key);
  public function store($key, $data);
  public function delete($key);
}

In turn you have both your ApcCacher and your new FileCacher classes implement the CacherInterface and you program your Controller class to use the capabilities required by the interface.

This example (hopefully) demonstrates how programming to an interface allows you to change the internal implementation of your classes without worrying if the changes will break your other code.

Traits

Traits, on the other hand, are simply a method for re-using code. Interfaces should not be thought of as a mutually exclusive alternative to traits. In fact, creating traits that fulfill the capabilities required by an interface is the ideal use case.

You should only use traits when multiple classes share the same functionality (likely dictated by the same interface). There's no sense in using a trait to provide functionality for a single class: that only obfuscates what the class does and a better design would move the trait's functionality into the relevant class.

Consider the following trait implementation:

interface Person
{
    public function greet();
    public function eat($food);
}

trait EatingTrait
{
    public function eat($food)
    {
        $this->putInMouth($food);
    }

    private function putInMouth($food)
    {
        // Digest delicious food
    }
}

class NicePerson implements Person
{
    use EatingTrait;

    public function greet()
    {
        echo 'Good day, good sir!';
    }
}

class MeanPerson implements Person
{
    use EatingTrait;

    public function greet()
    {
        echo 'Your mother was a hamster!';
    }
}

A more concrete example: imagine both your FileCacher and your ApcCacher from the interface discussion use the same method to determine whether a cache entry is stale and should be deleted (obviously this isn't the case in real life, but go with it). You could write a trait and allow both classes to use it to for the common interface requirement.

One final word of caution: be careful not to go overboard with traits. Often traits are used as a crutch for poor design when unique class implementations would suffice. You should limit traits to fulfilling interface requirements for best code design.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 85
    I was really looking for the quick simple answer that was provided above, but I have to say that you gave an excellent in-depth answer that will help make the distinction clearer for others, kudos. – datguywhowanders Feb 09 '12 at 14:56
  • 43
    "[C]reating traits that fulfill the capabilities required by an interface in a given class is an ideal use case". Exactly: +1 – Alec Gorge Feb 09 '12 at 20:38
  • 7
    Would it be fair to say that traits in PHP are similar to mixins in other languages? – Eno Jul 05 '12 at 15:22
  • Great explanation! Looks like an interface and a trait used together provides a class that implement/use them with the same benefits that it can get from extending an abstract class. – Jannie Theunissen Aug 21 '12 at 07:42
  • @rdlowrey I've never seen such a good answer about the differences between traits and interfaces in PHP written by someone named Daniel. – Lusitanian Aug 22 '12 at 02:07
  • Really well written answer. _b – Sam Williams Aug 22 '12 at 05:24
  • Great answer! One thing stays unclear to me though. How are PHP's traits different from multiple inheritance? Doesn't using multiple traits do **exactly the same** thing extending multiple classes would? (if it were possible in PHP) –  Apr 01 '13 at 16:45
  • 7
    @igorpan For all intents and purposes I would say PHP's trait implementation *is* the same as multiple inheritance. It's worth noting that if a trait in PHP specifies static properties then each class using the trait will have its own copy of the static property. **More importantly ...** seeing how this post is now extremely high on the SERPs when querying for traits I'm going to add a public service announcement to the top of the page. You should read it. –  Apr 01 '13 at 17:07
  • Thanks. I agree about the "code smell", I really did a bit of research today on traits and I really can't see good use for them. At least not in situations I encountered yet. –  Apr 01 '13 at 22:56
  • 3
    +1 for in-depth explanation. I come from a ruby background, where mixins are used a LOT; just to add my two cents, a good rule of thumb we use could be translated in php as "do not implement methods that mutate $this in traits". This prevents a whole bunch of crazy debugging sessions... A mixin should also NOT make any assumptions on the class it will be mixed in (or you should make it very clear and reduce the dependencies to a bare minimum). In this regard, I find your idea of traits implementing interfaces nice. – m_x Apr 11 '13 at 07:53
  • 2
    Outstanding answer. Really nailing the power of interfaces as well as plenty of great info (and caveats) about traits. Sort of confirms some of my misgivings about them - they made me feel a little funny, but I wasn't sure why until I read this :D – Darragh Enright Mar 06 '14 at 12:08
  • So with the Person interface example, the same end-result could have been achieved with an abstract class EatingPerson that implements the interface and that NicePerson and MeanPerson could both extend from. Is there a solid example where two other implementing classes use a different trait (from the first two) to satisfy the interface's eat method requirement? I can think of some that might be in smelly territory – Anthony Mar 26 '15 at 09:24
  • Also, if there is no indicator to check/enforce which trait is being used, this seems risky if, say, one variation of putInMouth has logic to test if spicy and if spicy , spit at food giver. I'd prefer to at least have the option of learning by error what the outcome is of an initially ambiguous trait. – Anthony Mar 26 '15 at 09:25
  • 2
    Answer is great, example of usage of traits is an example, but no point in using them there, wonder why? Because there is none! – Sofija Oct 28 '15 at 20:35
  • What the difference between an `Interface` and a `Trait` with abstract methods? – Ariel Jan 15 '17 at 23:51
  • Trait is the only good thing I miss in PHP since I left it (now on C#). The power it gives is something unique. – nawfal May 10 '17 at 14:13
  • 1
    You opinion is based assumption that all the problems in world can be solved using OOPS and there is no scope of improvement in Classical OOPS Concept which in itself is wrong assumption, Lets take example of JAVA8 with its new JAVASCRIPT like features, my point there is always scope for improvement. Nothing is absolute, otherwise you would never invent something new. – LNT Jun 08 '17 at 08:14
  • I would add in the "PSA" the line about "creating traits that fulfill the capabilities required by an interface is the ideal use case.". This is as important as the "code smell" part. – tdtm May 17 '18 at 15:40
  • I however do not think the `Person` and `EatingTrait ` is a great exemple, as that could be done by having an abstract `Person` class that implements `eat` and has an abstract `greet` method. It would make more sense if you were reusing a method with something that doesn't logically share a common parent with `Person` so, say, `greet` was `use`'d for a `Robot` (which doesn't eat and isn't a `Person`). – tdtm May 17 '18 at 15:43
  • That is the most relevant use case for traits you described. [imho] – Raisch Oct 27 '18 at 11:52
  • This is very biased comparison and it does not do justice to traits. Main purpose of traits is composition yet you say avoid it in favor of composition. Traits should abstract behavior, method conflicts does not make sense unless it is not well thought or planned. Still, you can resolve it. The real problem is how Traits are implemented for PHP. It is sloppy and not well thought, does not reflect true purpose of traits. It could be implemented as an alternative to OOP and independent of it. It could make PHP way better language. Another missed opportunity. – snnsnn Sep 19 '20 at 08:24
260

An interface defines a set of methods that the implementing class must implement.

When a trait is use'd the implementations of the methods come along too--which doesn't happen in an Interface.

That is the biggest difference.

From the Horizontal Reuse for PHP RFC:

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.

Chris Bornhoft
  • 4,195
  • 4
  • 37
  • 55
Alec Gorge
  • 17,110
  • 10
  • 59
  • 71
  • To be fair, that isn't in the standard PHP documentation, it is from the rfc when the idea was proposed to be added to core. – Alec Gorge Feb 09 '12 at 20:37
  • 1
    It seems exactly like an Abstract class without having to be extended, and implemented with the keyword "use". Is that accurate? If not what's off about what I just said? – JREAM May 09 '12 at 01:42
  • 2
    @JREAM In practice, nothing. In reality, much more. – Alec Gorge May 09 '12 at 11:22
  • 83
    Except that traits are not interfaces at all. Interfaces are specification that can be checked against. Traits cannot be checked against, hence they are implementation only. They are the exact opposite of interfaces. That line in the RFC is simply wrong... – ircmaxell May 09 '12 at 12:23
  • So they're something in between interfaces and abstract classes? I mean you can implement logic as in an abstract class and "implement" various traits? – orlybg Nov 13 '12 at 18:06
  • 216
    Traits are essentially **language assisted copy and paste**. – Shahid Nov 14 '12 at 05:58
  • 12
    That's not a metaphor. That's butchering the meaning of a word. It's like describing a box as a surface with volume. – cleong Nov 27 '12 at 08:02
  • Wow - I never knew about this! I've wanted this feature in a language for a LONG time. It solves the problems that multiple inheritance and interfaces couldn't - namely, code reuse without retyping or extending. I actually ran into an issue with this here: http://stackoverflow.com/q/5670917/677526 –  Nov 29 '12 at 18:52
  • 7
    To expand on ircmaxell's and Shadi's comments: You can check whether an object implements an interface (via instanceof), and you can ensure that a method argument implements an interface via a type hint in the method signature. You can't perform corresponding checks for traits. – Brian D'Astous Dec 24 '13 at 01:30
  • That RFC line is painfully wrong. Traits are little more than php implemented mixins. They don't define a contract and they can't be checked against. Nothing close to what an interface is. – Seph Jul 28 '14 at 23:01
  • 1
    Traits bring functionality into your class with methods/properties wheres interface is just a blueprint for your class (nothing is added but it dictates what must be there - more like a class template). – bpile Oct 17 '18 at 09:48
  • Traits become dependencies that you can't invert control over. – Kamafeather Nov 21 '18 at 22:34
  • @Shahid if that were true this case won't exist :https://stackoverflow.com/questions/59732901/understanding-php-traits-scope – Bobby Axe Jan 14 '20 at 11:47
  • Trait is a big word for an include file. It could even define an interface. Interfaces ensure code "interfaces" to a defined set of functions, A trait is a horrible way of "including" stuff. Terrible "advance". – RichieHH Jan 16 '20 at 02:29
76

A trait is essentially PHP's implementation of a mixin, and is effectively a set of extension methods which can be added to any class through the addition of the trait. The methods then become part of that class' implementation, but without using inheritance.

From the PHP Manual (emphasis mine):

Traits are a mechanism for code reuse in single inheritance languages such as PHP. ... It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance.

An example:

trait myTrait {
    function foo() { return "Foo!"; }
    function bar() { return "Bar!"; }
}

With the above trait defined, I can now do the following:

class MyClass extends SomeBaseClass {
    use myTrait; // Inclusion of the trait myTrait
}

At this point, when I create an instance of class MyClass, it has two methods, called foo() and bar() - which come from myTrait. And - notice that the trait-defined methods already have a method body - which an Interface-defined method can't.

Additionally - PHP, like many other languages, uses a single inheritance model - meaning that a class can derive from multiple interfaces, but not multiple classes. However, a PHP class can have multiple trait inclusions - which allows the programmer to include reusable pieces - as they might if including multiple base classes.

A few things to note:

                      -----------------------------------------------
                      |   Interface   |  Base Class   |    Trait    |
                      ===============================================
> 1 per class         |      Yes      |       No      |     Yes     |
---------------------------------------------------------------------
Define Method Body    |      No       |       Yes     |     Yes     |
---------------------------------------------------------------------
Polymorphism          |      Yes      |       Yes     |     No      |
---------------------------------------------------------------------

Polymorphism:

In the earlier example, where MyClass extends SomeBaseClass, MyClass is an instance of SomeBaseClass. In other words, an array such as SomeBaseClass[] bases can contain instances of MyClass. Similarly, if MyClass extended IBaseInterface, an array of IBaseInterface[] bases could contain instances of MyClass. There is no such polymorphic construct available with a trait - because a trait is essentially just code which is copied for the programmer's convenience into each class which uses it.

Precedence:

As described in the Manual:

An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in return override inherited methods.

So - consider the following scenario:

class BaseClass {
    function SomeMethod() { /* Do stuff here */ }
}

interface IBase {
    function SomeMethod();
}

trait myTrait {
    function SomeMethod() { /* Do different stuff here */ }
}

class MyClass extends BaseClass implements IBase {
    use myTrait;

    function SomeMethod() { /* Do a third thing */ }
}

When creating an instance of MyClass, above, the following occurs:

  1. The Interface IBase requires a parameterless function called SomeMethod() to be provided.
  2. The base class BaseClass provides an implementation of this method - satisfying the need.
  3. The trait myTrait provides a parameterless function called SomeMethod() as well, which takes precedence over the BaseClass-version
  4. The class MyClass provides its own version of SomeMethod() - which takes precedence over the trait-version.

Conclusion

  1. An Interface can not provide a default implementation of a method body, while a trait can.
  2. An Interface is a polymorphic, inherited construct - while a trait is not.
  3. Multiple Interfaces can be used in the same class, and so can multiple traits.
Troy Alford
  • 26,660
  • 10
  • 64
  • 82
  • 5
    "A trait is similar to the C# concept of an abstract class" No, an abstract class is an abstract class; that concept exists in both PHP and C#. I would compare a trait in PHP to a static class made of extension methods in C# instead, with the type-based restriction removed as a trait can be used by pretty much any type, unlike an extension method which only extends one type. – BoltClock Jan 01 '14 at 06:13
  • 1
    Very good commentary - and I agree with you. In re-reading, that is a better analogy. I believe that it's better still, though, to think of it as a `mixin` - and as I've revisited the opening of my answer, I've updated to reflect this. Thanks for commenting, @BoltClock! – Troy Alford Jan 05 '14 at 00:10
  • 1
    I don't think that there is any relation to c# extension methods. Extension methods are added to the single class type(respecting class hierarchy of course) their's purpose is to enhance a type with additional functionality, not to "share code" over multiple classes and make a mess. It's not comparable! If something needs to be reused, it usually means it should have space of it's own, like separate class which would be related to the classes that need common functionality. Implementation can vary depending on design, but roughly that's that. Traits are just another way to make a poor code. – Sofija Oct 28 '15 at 20:28
  • A class can have multiple Interface? I'm not sure if I'm getting your graph wrong, but class X implements Y,Z is valid. – Yann Chabot Dec 15 '16 at 21:40
32

I think traits are useful to create classes that contain methods that can be used as methods of several different classes.

For example:

trait ToolKit
{
    public $errors = array();

    public function error($msg)
    {
        $this->errors[] = $msg;
        return false;
    }
}

You can have and use this "error" method in any class that uses this trait.

class Something
{
    use Toolkit;

    public function do_something($zipcode)
    {
        if (preg_match('/^[0-9]{5}$/', $zipcode) !== 1)
            return $this->error('Invalid zipcode.');
        
        // do something here
    }
}

While with interfaces you can only declare the method signature, but not its functions' code. Also, to use an interface you need to follow a hierarchy, using implements. This is not the case with traits.

It is completely different!

Kresten
  • 100
  • 2
  • 9
J. Bruni
  • 20,322
  • 12
  • 75
  • 92
  • I think this is a bad example of a trait. `to_integer` would be more likely included in an `IntegerCast` interface because there is no fundamentally similar way to (intelligently) cast classes to an integer. – Matthew Feb 09 '12 at 04:13
  • 5
    Forget "to_integer" - it's just an illustration. An example. A "Hello, World". An "example.com". – J. Bruni Feb 09 '12 at 04:15
  • 2
    What benefit does this toolkit trait provide that a standalone utility class couldn't? Instead of `use Toolkit` you could have `$this->toolkit = new Toolkit();` or am I missing some benefit of the trait itself? – Anthony Mar 26 '15 at 10:17
  • @Anthony somewhere in your `Something`'s container you do `if(!$something->do_something('foo')) var_dump($something->errors);` – TheRealChx101 Apr 17 '15 at 03:29
28

For beginners above answer might be difficult, this is the easiest way to understand it:

Traits

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

so if you want to have sayHello function in other classes without re-creating the whole function you can use traits,

class MyClass{
  use SayWorld;

}

$o = new MyClass();
$o->sayHello();

Cool right!

Not only functions you can use anything in the trait(function, variables, const...). Also, you can use multiple traits: use SayWorld, AnotherTraits;

Interface

  interface SayWorld {
     public function sayHello();
  }

  class MyClass implements SayWorld { 
     public function sayHello() {
        echo 'World!';
     }
}

So this is how interfaces differ from traits: You have to re-create everything in the interface in an implemented class. Interfaces don't have an implementation and interfaces can only have functions and constants, it cannot have variables.

I hope this helps!

Kresten
  • 100
  • 2
  • 9
Supun Praneeth
  • 3,087
  • 2
  • 30
  • 33
8

Traits are simply for code reuse.

Interface just provides the signature of the functions that is to be defined in the class where it can be used depending on the programmer's discretion. Thus giving us a prototype for a group of classes.

For reference- http://www.php.net/manual/en/language.oop5.traits.php

Rajesh Paul
  • 6,793
  • 6
  • 40
  • 57
6

An often-used metaphor to describe Traits is Traits are interfaces with implementation.

This is a good way of thinking about it in most circumstances, but there are a number of subtle differences between the two.

For a start, the instanceof operator will not work with traits (ie, a trait is not a real object), therefore you can't use that to see if a class has a certain trait (or to see if two otherwise unrelated classes share a trait). That's what they mean by it being a construct for horizontal code re-use.

There are functions now in PHP that will let you get a list of all the traits a class uses, but trait-inheritance means you'll need to do recursive checks to reliably check if a class at some point has a specific trait (there's example code on the PHP doco pages). But yeah, it's certainly not as simple and clean as instanceof is, and IMHO it's a feature that would make PHP better.

Also, abstract classes are still classes, so they don't solve multiple-inheritance related code re-use problems. Remember you can only extend one class (real or abstract) but implement multiple interfaces.

I've found traits and interfaces are really good to use hand in hand to create pseudo multiple inheritance. Eg:

class SlidingDoor extends Door implements IKeyed  
{  
    use KeyedTrait;  
    [...] // Generally not a lot else goes here since it's all in the trait  
}

Doing this means you can use instanceof to determine if the particular Door object is Keyed or not, you know you'll get a consistent set of methods, etc, and all the code is in one place across all the classes that use the KeyedTrait.

Kresten
  • 100
  • 2
  • 9
Jon Marnock
  • 3,155
  • 1
  • 20
  • 15
  • The last part of that answer is of course what @rdlowrey is saying in more detail in the last three paragraphs under "Traits" in his post; I just felt a really simple skeleton code snippet would help to illustrate it. – Jon Marnock Apr 19 '12 at 05:25
  • I think the best OO way to use traits is using interfaces where you can. And if there is a case when multiple subclasses implementing the same kind of code for that interface and you can't move that code to their (abstract) superclass -> implement it with traits – Johannes Reiners Aug 17 '12 at 08:13
4

You can consider a trait as an automated "copy-paste" of code, basically.

Using traits is dangerous since there is no mean to know what it does before execution.

However, traits are more flexible because of their lack of limitations such as inheritance.

Traits can be useful to inject a method which checks something into a class, for example, the existence of another method or attribute. A nice article on that (but in French, sorry).

For French-reading people who can get it, the GNU/Linux Magazine HS 54 has an article on this subject.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Benj
  • 1,184
  • 7
  • 26
  • 57
  • Still don't get how traits are different from interfaces with default implementation – denis631 Dec 10 '18 at 11:46
  • @denis631 You can see Traits as snippets of code, and interfaces as signature contracts. If it can help, you can see it as an informal bit of a class that can contain anything. Let me know if it helps. – Benj Dec 14 '18 at 22:53
  • 1
    I see that PHP traits can be seen as macros which are then expanded at compile time / just aliasing that code snippet with that key. Rust traits, however, appear different (or am I wrong). But since they both have word trait in it I would assume for them to be the same, meaning the same concept. Rust traits link: https://doc.rust-lang.org/rust-by-example/trait.html – denis631 Dec 15 '18 at 15:30
2

If you know English and know what trait means, it is exactly what the name says. It is a class-less pack of methods and properties you attach to existing classes by typing use.

Basically, you could compare it to a single variable. Closures functions can use these variables from outside of the scope and that way they have the value inside. They are powerful and can be used in everything. Same happens to traits if they are being used.

Thielicious
  • 4,122
  • 2
  • 25
  • 35
2

Other answers did a great job of explaining differences between interfaces and traits. I will focus on a useful real world example, in particular one which demonstrates that traits can use instance variables - allowing you add behavior to a class with minimal boilerplate code.

Again, like mentioned by others, traits pair well with interfaces, allowing the interface to specify the behavior contract, and the trait to fulfill the implementation.

Adding event publish / subscribe capabilities to a class can be a common scenario in some code bases. There's 3 common solutions:

  1. Define a base class with event pub/sub code, and then classes which want to offer events can extend it in order to gain the capabilities.
  2. Define a class with event pub/sub code, and then other classes which want to offer events can use it via composition, defining their own methods to wrap the composed object, proxying the method calls to it.
  3. Define a trait with event pub/sub code, and then other classes which want to offer events can use the trait, aka import it, to gain the capabilities.

How well does each work?

#1 Doesn't work well. It would, until the day you realize you can't extend the base class because you're already extending something else. I won't show an example of this because it should be obvious how limiting it is to use inheritance like this.

#2 & #3 both work well. I'll show an example which highlights some differences.

First, some code that will be the same between both examples:

An interface

interface Observable {
    function addEventListener($eventName, callable $listener);
    function removeEventListener($eventName, callable $listener);
    function removeAllEventListeners($eventName);
}

And some code to demonstrate usage:

$auction = new Auction();

// Add a listener, so we know when we get a bid.
$auction->addEventListener('bid', function($bidderName, $bidAmount){
    echo "Got a bid of $bidAmount from $bidderName\n";
});

// Mock some bids.
foreach (['Moe', 'Curly', 'Larry'] as $name) {
    $auction->addBid($name, rand());
}

Ok, now lets show how the implementation of the Auction class will differ when using traits.

First, here's how #2 (using composition) would look like:

class EventEmitter {
    private $eventListenersByName = [];

    function addEventListener($eventName, callable $listener) {
        $this->eventListenersByName[$eventName][] = $listener;
    }

    function removeEventListener($eventName, callable $listener) {
        $this->eventListenersByName[$eventName] = array_filter($this->eventListenersByName[$eventName], function($existingListener) use ($listener) {
            return $existingListener === $listener;
        });
    }

    function removeAllEventListeners($eventName) {
        $this->eventListenersByName[$eventName] = [];
    }

    function triggerEvent($eventName, array $eventArgs) {
        foreach ($this->eventListenersByName[$eventName] as $listener) {
            call_user_func_array($listener, $eventArgs);
        }
    }
}

class Auction implements Observable {
    private $eventEmitter;

    public function __construct() {
        $this->eventEmitter = new EventEmitter();
    }

    function addBid($bidderName, $bidAmount) {
        $this->eventEmitter->triggerEvent('bid', [$bidderName, $bidAmount]);
    }

    function addEventListener($eventName, callable $listener) {
        $this->eventEmitter->addEventListener($eventName, $listener);
    }

    function removeEventListener($eventName, callable $listener) {
        $this->eventEmitter->removeEventListener($eventName, $listener);
    }

    function removeAllEventListeners($eventName) {
        $this->eventEmitter->removeAllEventListeners($eventName);
    }
}

Here's how #3 (traits) would look like:

trait EventEmitterTrait {
    private $eventListenersByName = [];

    function addEventListener($eventName, callable $listener) {
        $this->eventListenersByName[$eventName][] = $listener;
    }

    function removeEventListener($eventName, callable $listener) {
        $this->eventListenersByName[$eventName] = array_filter($this->eventListenersByName[$eventName], function($existingListener) use ($listener) {
            return $existingListener === $listener;
        });
    }

    function removeAllEventListeners($eventName) {
        $this->eventListenersByName[$eventName] = [];
    }

    protected function triggerEvent($eventName, array $eventArgs) {
        foreach ($this->eventListenersByName[$eventName] as $listener) {
            call_user_func_array($listener, $eventArgs);
        }
    }
}

class Auction implements Observable {
    use EventEmitterTrait;

    function addBid($bidderName, $bidAmount) {
        $this->triggerEvent('bid', [$bidderName, $bidAmount]);
    }
}

Note that the code inside the EventEmitterTrait is exactly the same as what's inside the EventEmitter class except the trait declares the triggerEvent() method as protected. So, the only difference you need to look at is the implementation of the Auction class.

And the difference is large. When using composition, we get a great solution, allowing us to reuse our EventEmitter by as many classes as we like. But, the main drawback is the we have a lot of boilerplate code that we need to write and maintain because for each method defined in the Observable interface, we need to implement it and write boring boilerplate code that just forwards the arguments onto the corresponding method in our composed the EventEmitter object. Using the trait in this example lets us avoid that, helping us reduce boilerplate code and improve maintainability.

However, there may be times where you don't want your Auction class to implement the full Observable interface - maybe you only want to expose 1 or 2 methods, or maybe even none at all so that you can define your own method signatures. In such a case, you might still prefer the composition method.

But, the trait is very compelling in most scenarios, especially if the interface has lots of methods, which causes you to write lots of boilerplate.

* You could actually kinda do both - define the EventEmitter class in case you ever want to use it compositionally, and define the EventEmitterTrait trait too, using the EventEmitter class implementation inside the trait :)

goat
  • 31,486
  • 7
  • 73
  • 96
1

The main difference is that, with interfaces, you must define the actual implementation of each method within each class that implements said interface, so you can have many classes implement the same interface but with different behavior, while traits are just chunks of code injected in a class; another important difference is that trait methods can only be class-methods or static-methods, unlike interface methods which can also (and usually are) be instance methods.

1

An interface is a contract that says “this object is able to do this thing”, whereas a trait is giving the object the ability to do the thing.

A trait is essentially a way to “copy and paste” code between classes.

Try reading this article, What are PHP traits?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mercury
  • 2,390
  • 3
  • 30
  • 39
1

The trait is same as a class we can use for multiple inheritance purposes and also code reusability.

We can use trait inside the class and also we can use multiple traits in the same class with 'use keyword'.

The interface is using for code reusability same as a trait

the interface is extend multiple interfaces so we can solve the multiple inheritance problems but when we implement the interface then we should create all the methods inside the class. For more info click below link:

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

Chirag Prajapati
  • 529
  • 6
  • 10