Vasanth Krishnamoorthy

Software Engineer (Http'ster)

PHP Traits – The Good, the Bad and the Ugly

Quite often we run into situations where we might have some methods that we would like to reuse in multiple classes, but they may not fit well due to the limitation of PHP’s single inheritance model. Today, we’ll look into traits which was introduced in PHP 5.4 to overcome these issues and where it should be used/avoided.

What are Traits?
Traits are basically just a collection of methods that let you share an implementation across inheritance hierarchies. It is a class like structure that cannot be instantiated. Think of it as includes for classes.

The Good
Traits are defined as “horizontal inheritance. Therefore it’s good to prevent the copy-paste anti-pattern. Given below is a basic example explaining traits functionality.

trait PriceUtilities
{
    private $taxrate = 8.2;

	public function calculateTax($price) {
		return (($this->taxrate / 100) * $price);
	}
}
 

class ShopProduct
{
	use PriceUtilities;
}

 
abstract class Service
{
	// service oriented stuff

}
 
class UtilityService extends Service
{
	use PriceUtilities;
}
 
$p = new ShopProduct();
print $p->calculateTax(100);

 
$u = new UtilityService();
print $u->calculateTax(100);

I declare the PriceUtilities trait with the trait keyword. The body of the trait looks very similar to that of a class. Now having declared and implemented the calculateTax() method in a single place, I go ahead and incorporate it into both the ShopProduct and the UtilityService classes.

The Bad
Besides traits being a nice mechanism for reusing code, they are also going to be a nightmare in the wrong hands. The dangers could be some of the following:

  • Risk of altering a trait thinking it will alter one type of class using it, but may introduce issues with other classes using it.
  • The idea of traits being used across multiple classes could potentially lead to conflicts in naming. You can solve it using insteadof keyword, but it’s now more things to worry about.

The Ugly
Traits are essentially language assisted copy and paste. The potential abuse of this feature is quite significant. Let’s go over some of it’s concerns

  • Tight Coupling
    Since traits are resolved at compile-time, the use is no different from extends in the sense that it tightly couples the trait implementation to the using class. This can actually reduce the re usability and utility of the class itself.
  • Testability
    Traits are essentially static access in disguise and static code is bad. They usually introduce these code smells:

    • Tight coupling, no way to exchange at runtime.
    • Static code cannot be overwritten through inheritance
    • Not testable in isolation
  • Single Responsibility Principle
    There are definitely cases where traits can be used to implement common functionality where inheritance cannot. However there’s also a temptation to implement all sorts of code in a trait and the available runtime object really does many things than needed.
  • Understandability
    Right now, to understand what a class you need to traverse up the inheritance chain to determine how it works. Traits introduce horizontal inheritance and class in the chain can have an arbitrary number of traits associated with it. This can make understanding a code base significantly harder.

Summary:
Traits help solve a specific problem of reuse between classes – but must be used with caution as a rule of thumb thinking about how we can solve the problem with aggregation can help avoid it in most cases.

DROP A COMMENT

Your email address will not be published. Required fields are marked *