Viewed   92 times

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.

 Answers

5

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.

Thursday, October 20, 2022
4

I don't know what your source is for the claim that you should prefer traits over abstract classes in Scala, but there are several reasons not to:

  1. Traits complicate Java compatibility. If you have a trait with a companion object, calling methods on the companion object from Java requires bizarre MyType$.MODULE$.myMethod syntax. This isn't the case for abstract classes with companion objects, which are implemented on the JVM as a single class with static and instance methods. Implementing a Scala trait with concrete methods in Java is even more unpleasant.
  2. Adding a method with an implementation to a trait breaks binary compatibility in a way that adding concrete methods to a class doesn't.
  3. Traits result in more bytecode and some additional overhead related to the use of forwarder methods.
  4. Traits are more powerful, which is bad—in general you want to use the least powerful abstraction that gets the job done. If you don't need the kind of multiple inheritance they support (and very often you don't), it's better not to have access to it.

The last reason is by far the most important in my view. At least a couple of the other issues might get fixed in future versions of Scala, but it will remain the case that defaulting to classes will constrain your programs in ways that are (at least arguably) consistent with good design. If you decide you actually really do want the power provided by traits, they'll still be there, but that'll be a decision you make, not something you just slip into.

So no, in the absence of other information, I'd suggest using an abstract class (ideally a sealed one) and two concrete classes that provide implementations.

Saturday, August 20, 2022
 
1

The really short version is simpler because you can't. That's not how Traits work.

When you write use SomeTrait; in PHP you are (effectively) telling the compiler to copy and paste the code from the Trait into the class where it's being used.

Because the use SomeTrait; is inside the class, it can't add implements SomeInterface to the class, because that has to be outside the class.

"why aren't Traits types in PHP? "

Because they can't be instantiated. Traits are really just a language construct (telling the compiler to copy and paste the trait code into this class) as opposed to an object or type that can be referenced by your code.

So, i want to "design" in the code that every class that want to use my trait have to implement the interface.

That can be enforced using an abstract class to use the trait and then extending classes from it.

interface SomeInterface{
    public function someInterfaceFunction();
}

trait SomeTrait {
    function sayHello(){
        echo "Hello my secret is ".static::$secret;
    }
}

abstract class AbstractClass implements SomeInterface{
    use SomeTrait;
}

class TestClass extends AbstractClass {
    static public  $secret = 12345;

    //function someInterfaceFunction(){
        //Trying to instantiate this class without this function uncommented will throw an error
        //Fatal error: Class TestClass contains 1 abstract method and must therefore be 
        //declared abstract or implement the remaining methods (SomeInterface::doSomething)
    //}
}

$test = new TestClass();

$test->sayHello();

However - if you do need to enforce that any class that uses a Trait has a particular method, I think you may be using traits where you should have been abstract classes in the first place.

Or that you have your logic the wrong way round. You're meant to require classes that implement interfaces have certain functions, not that if they have certain functions that they must declare themselves as implementing an interface.

Edit

Actually you can define abstract functions inside Traits to force a class to implement the method. e.g.

trait LoggerTrait {

    public function debug($message, array $context = array()) {
        $this->log('debug', $message, $context);
    }

    abstract public function log($level, $message, array $context = array());
}

However this still doesn't allow you to implement the interface in the trait, and still smells like a bad design, as interfaces are much better than traits at defining a contract that a class needs to fulfill.

Sunday, November 27, 2022
 
5

I think there is some philosophical difference on how and when to use them.

You said :

  1. abstract classes: "anything using me will be using these methods and attributes"
  2. interfaces:"anything using me must have these methods and attributes"
  3. traits: "anything using me will also have these methods and attributes".

If you focus on your own wordings it makes sense.

Abstract Classes are in reality define things that are abstract e.g Vehicle is an abstract thing until or unless its materialized in the form of a car or a bike . Neither interface define it nor traits.

Interfaces compliment the class inheritance functionality where a class inherits from multiple classes(only certain languages provide multiple inheritance e.g C/C++). Interfaces , as names suggest focus on the INTERFACE , and not the implementation of the interface method in class which is implementing it. It makes classes PLUG & PLAYABLE so everyone should follow a standard. If you further read about factory and adapter pattern on OOP you will understand it.

Traits have implementation/functionality that is not bound to specific classes.Instead it could be found across different classes. Its like a gene in genetics which stays mute in parents and appear only in certain children. Or to be concise selective inheritance but not bound to single class. So it provides a way much better code-reuse

Edit Interface + Trait != Abstract Class , because when using Trait inheritance is selective as you select specific trait to use and while using Abstract Class inheritance is mandatory or dictated by parent class you don't have freedom!

Friday, November 4, 2022
 
fontno
 
1

When the Scala 2.11 compiler compiles a trait, it doesn't generate an interface with default methods, because the generated code has to work with Java 6. In Scala 2.12 (which requires Java 8) it will, so if you compile your Scala code with 2.12 compiler, I expect that you should be able to use it from Java in this way (at least for a simple case like this).

Note that changes like this are precisely what makes different Scala versions binary incompatible: if you tried to use a trait compiled with Scala 2.11 from Scala 2.12, it would try to call interface's default methods, which aren't there.

Wednesday, August 17, 2022
 
ravishi
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :