In the inheritance chapter, we learned how to extend classes to share common functionality. The problem with extending classes, is that you can only extend one. This is a little limiting.
Implementation
In PHP 5.4 a new construct, called a 'trait', was introduced to the language. Using traits, it was now possible for PHP classes to inherit methods and properties from multiple sources. A direct solution to the problem of single inheritance.
Let's take a look at a trait, shall we?
<?php
trait SomethingTrait
{
}
As you can see, a trait looks very similar to a class. Instead, it is declared using the trait
keyword. The convention of naming a trait with the Trait
suffix is quite a popular one, so it might be something that you should consider adopting.
Unlike a class, what's important to remember, is that you cannot add extends
or implements
to a trait. You can't instantiate a trait, either. Their sole purpose is to support our classes, and not to replace them.
Traits can have methods, just like classes do. For a moment, let's think back to our Animal
class. Do you remember it? Here it is once again to refresh our memory.
<?php
abstract class Animal
{
}
Our class called Animal
is an abstract one. This means that it's meant to be extended by our classes that represent actual animals.
Consider the possibility that we'd like to add a stroke()
method. For example, we'd like to stroke()
our red pandas to make them purr. We could add something like the following.
<?php
abstract class Animal
{
/**
* Stroke the animal.
*
* @return void
*/
public function stroke()
{
echo 'This animal purrs contently.';
}
}
Sure! That would work, right? The trouble is, you wouldn't stroke a snake, would you? No, it doesn't make sense to stroke every animal... Hmm, what can we do? Oh right, traits!
You see, traits are perfect for adding a new.. well... trait, to an object. We want to add a trait to animals which are strokeable, so what we're looking for is a StrokeableTrait
. Sure, that makes sense to me! Let's get going with this idea.
<?php
trait StrokeableTrait
{
/**
* Stroke the animal.
*
* @return void
*/
public function stroke()
{
echo 'This animal purrs contently.';
}
}
We've gone ahead and moved the stroke()
method to the trait. You'll find no other differences here. This means, that we can also remove the method from Animal
, like this.
<?php
abstract class Animal
{
}
Perfect, we're all set. Let's create a red panda class, shall we? After all, that's what this book is all about. Well, that and PHP I suppose...
class RedPanda extends Animal
{
/**
* The panda's name.
*
* @var string
*/
private $name = 'Jasmina';
}
Beautiful, isn't she? We've extended the Animal
class, and while it might be empty at the moment, go ahead and assume that it could be full of useful methods such as eat()
, sleep()
and poop()
for example.
Now, let's think about our Panda for a moment. She's definitely strokeable, isn't she? Let's go ahead and use the trait.
<?php
class RedPanda extends Animal
{
use StrokeableTrait;
/**
* The panda's name.
*
* @var string
*/
private $name = 'Jasmina';
}
I find this a little bit annoying, but unfortunately, the keyword used to apply a trait to a class is once again the use
keyword. This is the same keyword that you'll find in the namespaces chapter. It's unfortunate naming, but it works all the same.
By placing the statement...
use StrokeableTrait;
... right inside the class, we've applied the trait, and our RedPanda
has gained the functionality from the trait.
Let's try using the method inherited from our trait.
<?php
// Create a new red panda.
$panda = new RedPanda;
// Stroke the panda.
$panda->stroke();
We create a new instance of the RedPanda
class, and call the stroke()
method directly. Let's see what happens.
This animal purrs contently.
That's purrrfect! Now, we've only used a single trait in this scenario, but it's entirely possible to use as many traits as you need. For example, the following is entirely legal.
<?php
class RedPanda extends Animal
{
use PlayableTrait;
use CareableTrait;
use StrokeableTrait;
/**
* The panda's name.
*
* @var string
*/
private $name = 'Jasmina';
}
Use traits to enhance the functionality of your classes. Of course, you can only use them on PHP version 5.4 or higher, so keep that in mind.
Priority
Now that you've learned about both inheritance and traits, you might be asking yourself a very fair question. What happens if we extend a class, and use a trait that both have a method of the same name.
The best way to demonstrate this, is by testing it out. Consider the following code sample.
<?php
trait TestTrait
{
public function test()
{
echo 'This is the trait method.';
}
}
class TestClass
{
public function test()
{
echo 'This is the class method.';
}
}
Here we have a TestTrait
and a TestClass
. They both have a method called test()
, which indicates the source of the method call.
It's time to setup our test-case.
<?php
// Define a class which extends the baseclass
// and implements the trait.
class Testing extends TestClass
{
use TestTrait;
}
// Create our testcase.
$test = new Testing;
// Run the test method.
$test->test();
We've created a class which extends the TestClass
and uses the TestTrait
. By calling the shared method test()
, we can find out which one takes priority from the output. Let's give it a go.
This is the trait method.
Sometimes, it's better to let the code answer our questions, don't you find? As we can see, the method within the trait, has taken priority over the method within the inherited class.
This means that we can use traits to override the functionality inherited from abstract classes. This is useful knowledge to a budding young programmer such as yourself. Use it wisely!
My books are available online for free to encourage learning. However, if you'd like for me to keep writing, then please consider buying a digital copy over at Leanpub.com.
It's available in PDF, ePub, and Kindle format, and contains a bunch of extras that you won't find on the site. I have a full-time job, and I write my books in my spare time. Please consider buying a copy so that I can continue to write new books from the comfort of my sofa!