Web Development With HHVM and Hack 16: Classes Part 6: Traits
In the last tutorial, we covered static functions in classes: https://medium.com/@mikeabelar/web-development-with-hhvm-and-hack-15-classes-part-5-33ae586a2f9d. In this tutorial, we will cover traits.
What Are Traits?
Traits are a powerful combination of interfaces and abstract classes. Traits allow you to define member variables and functions. The functions may or may not have implementations. Traits cannot be initialized on their own. Traits are most used when you want to incorporate unrelated code into a class. Abstract classes and interfaces should be used for related code. For example, if you are trying to represent a Dog and an Animal in code, then an interface or an abstract class makes the most sense. However, if the Dog class wants to use functions related to a Chair, then the Dog class should use the Chair trait as the two sets of functions are unrelated. In summary, it does not always make sense to extend an abstract class or implement an interface.
Another key distinction with traits is that like interfaces, a class can use multiple traits whereas only one abstract class can be used for each class. Traits themselves can use multiple other traits.
An Example
What I wrote is a lot to absorb so let us walk through an example:
// define a trait
trait Weather {
// you can declare member variables
private string $weather = "sunny";
// you can define functions
public function sayWeather(): void {
print("The weather outside today is ".$this->weather."\n");
} public function sayIsClouds(): void {
print("No clouds\n");
} // you can also leave declarations with no implementations
// use the abstract keyword to do this
public abstract function sayIsRain(): void;
}trait AnotherTrait {
public function anotherPrintFunction(): void {
print("Another print function\n");
}
}trait Raining {
// With this line, Raining now has access everything in Weather
use Weather;
// get access to everything in AnotherTrait
use AnotherTrait; // implement sayIsRain which was not implemented
public function sayIsRain(): void {
print("There is rain\n");
} // override the implementation of a trait in a function
<<__Override>>
public function sayIsClouds(): void {
print("There are clouds\n");
}}// need a class to use a trait
// because traits cannot be created on their own
class Person {
// the use keyword allows us to use the traits
use Raining;
// rest of the class as usual
private string $name;
public function __construct(string $n) {
$this->name = $n;
}
public function sayName(): void {
print("My name is ".$this->name."\n");
}
}<<__EntryPoint>>
function main(): noreturn {
$person = new Person("Bob");
$person->sayWeather();
$person->sayIsClouds();
$person->sayIsRain();
$person->anotherPrintFunction();
exit(0);
}
When run, the code outputs:
The weather outside today is sunny
There are clouds
There is rain
Another print function
Let us start from the top and work out way down starting with the Weather
trait. We define a trait using the trait
keyword followed by the name of the trait. We can define a member variable as we do in any class as we see with weather
. The sayWeather
function demonstrates that we can define and implement a function while the sayIsRain
function demonstrates that we can define abstract functions. We also define another trait, AnotherTrait
which only has one function.
Moving to the Raining
trait, we see that we include the other two traits (we can use as many as we would like) using the use
keyword which gives us access to the variables and the functions of the other traits. We go about implementing sayIsRain
which was declared abstract in the Weather
trait. Additionally, we override the implementation of sayIsClouds
by typing <<__Override>>
above the function to indicate that we are applying a new implementation. Finally, in the Person
class we use use Raining;
to include the trait (we use a trait because the implementation of Raining is unrelated to a Person).
In the next tutorial, we cover null and types: https://medium.com/@mikeabelar/web-development-with-hhvm-and-hack-17-types-and-null-be29a7d36ab5