假设我们有一个日志记录接口:
interface Logger { function log($message); }
现在说我们有两个Logger接口的具体实现:FileLogger和和ConsoleLogger。
class FileLogger implements Logger { public function log($message) { // 将日志消息追加到某些文件 } } class ConsoleLogger implements Logger { public function log($message) { // 将消息记录到控制台 } }
现在,如果您定义了一些Foo您还希望能够执行日志记录任务的类,则可以执行以下操作:
class Foo implements Logger { private $logger; public function setLogger(Logger $logger) { $this->logger = $logger; } public function log($message) { if ($this->logger) { $this->logger->log($message); } } }
Foo现在也是Logger,但其功能取决于Logger通过传递给它的实现setLogger()。如果现在我们希望类Bar也具有此日志记录机制,则必须在Bar类中复制此逻辑。
无需复制代码,可以定义一个特征:
trait LoggableTrait { protected $logger; public function setLogger(Logger $logger) { $this->logger = $logger; } public function log($message) { if ($this->logger) { $this->logger->log($message); } } }
现在,我们已经在特征中定义了逻辑,我们可以使用特征将逻辑添加到Foo和Bar类中:
class Foo { use LoggableTrait; } class Bar { use LoggableTrait; }
并且,例如,我们可以使用这样的Foo类:
$foo = new Foo(); $foo->setLogger( new FileLogger() ); //注意我们如何使用特征作为“代理”来调用Foo实例上的Logger的log方法 $foo->log('my beautiful message');