27

I was reading an article about the new features in PHP 5.4.0. One of the most anticipated one being Traits.

Reading up on these Traits, to see what they're all about, they simply look as compiler assisted copy-paste to me; and a language provided way to use composition, very much as used in the well-known Strategy Pattern which leverages the 'favor composition over inheritance' design principle.

Am I understanding this correctly?

What other advantages might these traits provide, that makes them worthwhile instead of just using the composition design principle?

hakre
  • 193,403
  • 52
  • 435
  • 836
nkr1pt
  • 4,691
  • 5
  • 35
  • 55

4 Answers4

25

No, traits are not simply composition due the fact that the rules by which traits are "pasted" into a class are completely different.

When using Composition, there is no chance for conflicts or methods overwriting because the composite element is a completely isolated unit (an instance of some other class) you interface with via it's public API from within the consuming instance. Also, if you need to provide access from the consuming instance, you'd have to add proxy methods to delegate to the composite element.

Traits on the other hand become part of the API of the very instance they are used in. They are not subsystems in the instance. They are not even instances but just a reusable boilerplate code. One benefit this provides is satisfying interfaces with a trait, as I have shown in Traits in PHP – any real world examples/best practices?

Community
  • 1
  • 1
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • 3
    Doesn't that make traits more risky than just composing an external instance into a class? What about conflicts with the trait's code blocks (methods? I don't know what you'd call them in a trait) and the host class methods? Or conflicts between the code blocks of multiple traits imported into the same class? Maybe I'm missing something but it seems to me that traits could get very messy very quickly if not used carefully. – GordonM Mar 02 '12 at 11:47
  • 1
    @GordonM: You need to resolve conflicts by definition, it's explained in the PHP manual ([Traits Precedence](http://php.net/traits#language.oop5.traits.precedence)). And sure, as with any language feature, you can mess things with traits. – hakre Mar 02 '12 at 11:54
  • OK, will take a look. However, I've got to say I don't think I'm very keen on the things so far. – GordonM Mar 02 '12 at 12:02
  • It's plenty useful in the right context, which is limited in scope but certainly common enough. – Jason Mar 16 '12 at 03:36
8

You have to be careful about the meaning you give to composition. In the more general sense, traits are a mechanism for decomposition as well as composition.

  • Decomposition -- how we decompose a software base into suitable units of reuse(code re-use, DRY).
  • Composition -- how we compose these units to obtain a class hierarchy suitable for our application domain.

Traits are a mechanism for composition in the sense that they can be composed with a class. Many trait implementations would also allow for traits to be composed with one another.

The GoF mantra is "favor composition over inheritance".

All class-based languages by default favor inheritance. Object can only acquire behaviours from their class or from classes higher in their inheritance chain. Sure you can achieve the same outcome in different ways. For instance, you can create a Manager Class (e.g., LayoutMananager) and then add a reference to it in any class that has a layable behavior/layout trait and add function that do nothing but call methods of the Manager

public function doSomething() { return layoutManager.doSomething(); }

Traits favor composition. Simple as that. The key characteristic of traits is that they live outside of the class hierarchy. You can "acquire" re-usable behaviors or traits without them coming from any of your super-class (the horizontal vs vertical distinction introduced in other posts). That's the main advantage.

The biggest issue with traits is the emergence of conflict when traits are implemented in a way that you can directly do myObject.doSomething() instead of myObject.trait1.doSometing() (directly, or indirectly as described above with layoutManager). Once you add more than one trait to a class, conflicts can easily emerge. Your implementation needs to support mechanisms like aliasing and override to help with conflict resolution. You get some overhead back.

It is not clear that the PHP implementation conform to this, but traits are also supposed to not specify any instance variables and the methods provided by traits should never directly access instance variables. (source: Adding Traits to (Statically Typed) Languages, PDF). This blog post discusses this. It claims that in PHP, the structure named trait really is a mixin (that is traits with state). (Though this other blog post describe them as stateless)

All, in all, thinking in terms of traits is likely to help write with better code. Writing your traits classes to avoid instantiation could also contribute to better code. This frees traits from any dependency, making it possible to call them in any order. But it is not clear that adding the concept of trait in the language itself would contribute to better code.

widged
  • 2,749
  • 21
  • 25
2

The traits "composition" (it's merely an include on the method level of classes) happens at compile time, whereas the composition you talk about is at runtime.

When you do that composition, the trait has already been there.

As the single inheritance in PHP and as well the often seen static utility classes hinder some design goals, traits offer another facet to shape your implementation and allow to reduce code-duplication.

hakre
  • 193,403
  • 52
  • 435
  • 836
1

traits are synonym of behaviour more than inheritance or decoration. It is not the same thing as strategy pattern because you can define a generic algorithme whereas each concrete strategy object has different algorithm. Moreover it is more a "horizontal" inheritance of a behaviour than a "vertical" inheritance with a specification of a behaviour.

The question is reallty interesting.

SERPRO
  • 10,015
  • 8
  • 46
  • 63
artragis
  • 3,677
  • 1
  • 18
  • 30