Я думаю, що вам доведеться вивчити мови, які мають риси, певний час, щоб вивчити прийняті добрі та найкращі практики. Моя поточна думка щодо Trait полягає в тому, що ви повинні використовувати їх лише для коду, який вам доведеться дублювати в інших класах, які мають однакові функції.
Приклад ознаки журналу:
interface Logger
{
public function log($message, $level);
}
class DemoLogger implements Logger
{
public function log($message, $level)
{
echo "Logged message: $message with level $level", PHP_EOL;
}
}
trait Loggable // implements Logger
{
protected $logger;
public function setLogger(Logger $logger)
{
$this->logger = $logger;
}
public function log($message, $level)
{
$this->logger->log($message, $level);
}
}
class Foo implements Logger
{
use Loggable;
}
І тоді ви робите ( демонстрація )
$foo = new Foo;
$foo->setLogger(new DemoLogger);
$foo->log('It works', 1);
Я думаю, що важливо, що слід враховувати при використанні ознак, - це те, що вони насправді є лише фрагментами коду, які копіюються в клас. Це може легко призвести до конфліктів, наприклад, при спробі змінити видимість методів, наприклад
trait T {
protected function foo() {}
}
class A {
public function foo() {}
}
class B extends A
{
use T;
}
Вищезазначене призведе до помилки ( демонстрації ). Аналогічно, будь-які способи, оголошені в ознаці, які також вже оголошені в використовуваному класі, не будуть скопійовані в клас, наприклад
trait T {
public function foo() {
return 1;
}
}
class A {
use T;
public function foo() {
return 2;
}
}
$a = new A;
echo $a->foo();
надрукує 2 ( демо ). Це те, чого ви хочете уникати, оскільки вони роблять помилки важкими. Ви також хочете уникати введення речей у ознаки, що діють на властивості або методи класу, який їх використовує, наприклад
class A
{
use T;
protected $prop = 1;
protected function getProp() {
return $this->prop;
}
}
trait T
{
public function foo()
{
return $this->getProp();
}
}
$a = new A;
echo $a->foo();
працює ( демонстрація ), але тепер риса тісно пов'язана з A і вся ідея горизонтального повторного використання втрачається.
Коли ви будете слідувати інтерфейс сегрегація Принцип ви будете мати багато дрібних класів і інтерфейсів. Це робить Риси ідеальним кандидатом для речей, про які ви згадали, наприклад, перехресного вирішення питань , але не для створення об'єктів (у структурному сенсі). У нашому прикладі Logger вище, ознака повністю ізольована. Він не має залежності від конкретних класів.
Ми могли б скористатися агрегацію / композицію (як показано в іншому місці на цій сторінці), щоб досягти того самого класу, що виходить, але недолік використання агрегації / складу полягає в тому, що нам доведеться додавати методи проксі / делегатора вручну до кожного класу, тоді, коли це повинно вміти входити в систему. Риси вирішують це чудово, дозволяючи мені тримати котельну плиту в одному місці і вибірково застосовувати її там, де потрібно.
Примітка: враховуючи, що ознаки є новим поняттям в PHP, вся думка, висловлена вище, може змінюватися. Я ще не мав багато часу, щоб сам оцінити цю концепцію. Але я сподіваюся, що це досить добре, щоб дати вам щось подумати.