Ich denke, man müsste sich schon seit einiger Zeit mit Sprachen befassen, die Eigenschaften haben, um die akzeptierten Good / Best Practices zu lernen. Meine aktuelle Meinung zu Trait ist, dass Sie sie nur für Code verwenden sollten, den Sie in anderen Klassen duplizieren müssten, die dieselbe Funktionalität haben.
Beispiel für ein Logger-Merkmal:
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;
}
Und dann machst du ( Demo )
$foo = new Foo;
$foo->setLogger(new DemoLogger);
$foo->log('It works', 1);
Ich denke, das Wichtigste bei der Verwendung von Merkmalen ist, dass es sich wirklich nur um Codeteile handelt, die in die Klasse kopiert werden. Dies kann leicht zu Konflikten führen, wenn Sie beispielsweise versuchen, die Sichtbarkeit von Methoden zu ändern, z
trait T {
protected function foo() {}
}
class A {
public function foo() {}
}
class B extends A
{
use T;
}
Das Obige führt zu einem Fehler ( Demo ). Ebenso werden im Merkmal deklarierte Methoden, die auch bereits in der using-Klasse deklariert sind, nicht in die Klasse kopiert, z
trait T {
public function foo() {
return 1;
}
}
class A {
use T;
public function foo() {
return 2;
}
}
$a = new A;
echo $a->foo();
druckt 2 ( Demo ). Dies sind Dinge, die Sie vermeiden möchten, da sie das Auffinden von Fehlern erschweren. Sie sollten auch vermeiden, Dinge in Merkmale zu setzen, die auf Eigenschaften oder Methoden der Klasse wirken, die sie verwendet, z
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();
funktioniert ( Demo ), aber jetzt ist das Merkmal eng mit A verbunden und die gesamte Idee der horizontalen Wiederverwendung geht verloren.
Wenn Sie dem Prinzip der Schnittstellentrennung folgen, haben Sie viele kleine Klassen und Schnittstellen. Das macht Traits zu einem idealen Kandidaten für die Dinge, die Sie erwähnt haben, z. B. Querschnittsthemen , aber keine Objekte (im strukturellen Sinne) zu komponieren. In unserem obigen Logger-Beispiel ist das Merkmal vollständig isoliert. Es gibt keine Abhängigkeiten von konkreten Klassen.
Wir könnten Aggregation / Komposition verwenden (wie an anderer Stelle auf dieser Seite gezeigt), um dieselbe resultierende Klasse zu erzielen, aber der Nachteil der Verwendung von Aggregation / Komposition besteht darin, dass wir die Proxy- / Delegator-Methoden manuell zu jeder Klasse hinzufügen müssen, die dies sollte in der Lage sein zu protokollieren. Eigenschaften lösen dieses Problem gut, indem ich die Kesselplatte an einem Ort aufbewahren und bei Bedarf selektiv anwenden kann.
Hinweis: Da Merkmale in PHP ein neues Konzept sind, können sich alle oben geäußerten Meinungen ändern. Ich hatte noch nicht viel Zeit, das Konzept selbst zu bewerten. Aber ich hoffe, es ist gut genug, um Ihnen etwas zum Nachdenken zu geben.