Traits can be viewed almost as an automation of Ctrl+C
and Ctrl+V
. This definition may seem coarse, but actually traits can be quite useful if used carefully in specific situations (more about this below).
It is recommended that you continue using interfaces to define contracts (as a project documentation) and abstract classes to implement the code groundwork of these contracts, leaving some more specific methods for their child classes to implement. Finally, if the hierarchy of classes for your project is important, keep doing it this way.
And as for the traits?
They definitely do not serve to define contracts. Traits completely ignore the class hierarchy. Use them to define very specific behaviors, which can be reused by different types of object. Among other things, they are very useful for classes that implement contracts that repeat several times.
For example: imagine you have the following base classes:
- Gambler
- Vehicle
- Gun
- Enemy
- Scenario
And the following daughter classes:
- Rafael
extends
Gambler
- Car
extends
Vehicle
- Motorbike
extends
Vehicle
- Magnum
extends
Gun
- AR-15
extends
Gun
- Knife
extends
Gun
- Soldier
extends
Enemy
- Monster
extends
Enemy
- Water
extends
Scenario
- Fire
extends
Scenario
- ...
- Tanquedeguerra
extends
Weapon or Vehicle?? What if it can be controlled? It’s a Player too? Look! It can also take damage!
In a case like this, traits would be useful to define very specific methods and properties that can be used by several objects of different types. For example:
//Pode ser type-hinted
Interface RecebeDano {
protected $vida;
public function foiAcertado($dano);
}
Interface CausaDano {
protected $dano;
public function acertou(RecebeDano $alvo);
}
//Pode ser usado pelas classes Jogador (com as mãos),
//Arma (todas), TanqueDeGuerra e Fogo (item do cenário)
Trait ImplementsCausaDano {
protected $dano = 10; //Pode ser sobrescrito pela classe
public function acertou(RecebeDano $alvo) {
$alvo->foiAcertado($this->dano);
}
}
"Ah, man, but this I can do with abstract class!"
Good, let’s take it easy there. You can only extend a single abstract class. That is, it clearly defines a parent-child relationship. If you want to force the hierarchy of classes, beauty. However, if you need a more flexible structure (like the tank example above), traits are the best way.
Important:
The methods of traits are evaluated as if they had been defined in the class that uses them, i.e.: it has priority over a method of a parent class with the same name.
The only entity that can override a trait method is the class that uses it itself, or another trait that has the same method. If the class that uses traits does not explicitly define which method prevails, it will cause a conflict.
In this case, PHP offers the following syntax to solve them:
class Classe {
use TraitA, TraitB {
TraitA::metodoDuplicado insteadof TraitB;
}
}
Finally, if you want to remember what each structure is intended to be, you can observe the semantics of the commands you write:
Interface you implements:
She’s a contract. She can’t implement anything, just define, but what she
defines you has to follow.
Abstract class you stretches: (inherits)
He is a father. He will help you in whatever you need to build your foundation, but some things you will have to do yourself.
Trait you uses:
It is a tool. You can use it for good or for evil. "With great powers come great responsibilities." (Ben, Tio)
Complicated this... +1
– Jorge B.
Cool question, I’m too lazy to give a long answer. I don’t know if the problem is having several questions in one, even if related. I think I’d answer if it weren’t so wide.
– Maniero
Come on, @bigown. It’s lunchtime, bro!
– Wallace Maxters
You noticed the downside of
trait
? http://php.net/manual/en/language.oop5.traits.php#107965– Guilherme Lautert
Vixi, @Guilhermelautert. Once again a language complication !
– Wallace Maxters
I’ve had colleagues who said "Trait is another PHP gambiara, this time to say you have multiple inheritance", I can’t say anything I never needed that kind of inheritance.
– Guilherme Lautert
Possible duplicate of What is the difference between Classes and Interfaces?
– Daniel Omine