23

My PHP applications are generally using classes for namespacing. The methods within these classes are defined as static.

Now that PHP has introduced Traits, I'm trying to wrap my head around when to use them. I saw some examples of using traits, but I'm thinking this could just as easily be implemented through a static class method.

A quite thorough example using a logger was listed here: Traits in PHP – any real world examples/best practices?

But why use a Trait, if you could also use a static Logger::log()? The only thing I can think of just now, is easy access to $this. Another example I am facing right now, is a user-exists function. Trait it, or static method it?

Can anyone shed some light on this?

Community
  • 1
  • 1
KrekkieD
  • 967
  • 9
  • 23
  • 1
    Both all pretty crap to use in a codebase imho. – PeeHaa Apr 19 '14 at 16:58
  • @PeeHaa please elaborate? – KrekkieD Apr 19 '14 at 17:01
  • Both make it hard to unit test your code, because of the tight coupling. As well as maintain / debug it because somehow some magic "external" piece of code is "imported" into the class. – PeeHaa Apr 19 '14 at 17:03
  • PHP has namespaces, why would you use a class for namespacing as well? – Brandon Buck Apr 19 '14 at 17:08
  • Traits simply allow you to emulate something like `class Foo extends Bar, Baz, Test, A, B` - its all about multiple inheritance. But you should be careful in order not to break the LSP (Liskov Substitution Principle) – Yang Apr 19 '14 at 17:13
  • 6
    Traits are mostly there to reduce code duplication. If a bunch of classes all have the same method, but are not logically connected so putting them in the same hierarchy and inheriting the method is not really possible, you can implement the method once and use it in all those classes via traits. "Traits vs. static" is a nonsensical question, as it's not an either-or thing really. Also see [How Not To Kill Your Testability Using Statics](http://kunststube.net/static/) – deceze Apr 19 '14 at 17:21
  • 1
    thanks guys. I have a better feel about it now. @deceze, that link is great, thanks, changed my view on writing static functions. – KrekkieD Apr 21 '14 at 07:46

3 Answers3

28

After reading the comments on the question, my take on the answer is this:

Traits allow the extending of a class without it being part of the class hierarchy. There's no need for something like class Book extends Loggable, as Book itself is not a Loggable, we just want the Loggable functionality. The functionality within the Loggable could be stuffed in a trait, therefore being able to use the Loggable methods within Book as though you were extending from it.

The advantage of using traits above the use of static methods within classes (or namespaced functions) is that the trait has access to the full class scope, also private members.

The downside of using static functions instead of traits, is tight coupling (dependencies) between the classes, which hurts reusability and can hurt unit testing (for instance when using mock services). Dependencies should be injected at runtime, which indeed increases the effort of instantiating a class/method, but allow better flexibility over the full app. This was a new insight for me.

KrekkieD
  • 967
  • 9
  • 23
4

I use traits only for simple helper methods [one-liners] (string regexp validations, string normalizers, primitiv number generators) which I need often in several classes.

When there were no traits, I used public static methods - with traits it's possible to define these as normal private methods, too.

Or you can use traits to define basic dummy functions in combination with classes with interfaces to make sure, every method exists.

The advantage of traits is that you can use the same methods in several classes, and for small changes you don't have to rewrite the same methods in all classes. Traits are just timesavers. ;)

And btw.. spl_autoload_register can handle the loading of trait-files, too. ;)

SammieFox
  • 554
  • 1
  • 6
  • 4
-4

Traits can access private members of objects.

Tomas
  • 1,531
  • 1
  • 16
  • 22