促进水平代码重用的特性

假设我们有一个用于记录的界面:

interface Logger {
    function log($message);
}

现在说我们有两个具体的 Logger 接口实现:FileLoggerConsoleLogger

class FileLogger implements Logger {
    public function log($message) {
        // Append log message to some file
    }
}

class ConsoleLogger implements Logger {
    public function log($message) {
        // Log message to the console
    }
}

现在,如果你定义了一些你也希望能够执行日志记录任务的其他类 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,但它的功能取决于通过 setLogger() 传递给它的 Logger 实现。如果我们现在希望类 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);
        }
    }
}

现在我们已经在 trait 中定义了逻辑,我们可以使用 trait 将逻辑添加到 FooBar 类:

class Foo {
    use LoggableTrait;
}

class Bar {
    use LoggableTrait;
}

并且,例如,我们可以像这样使用 Foo 类:

$foo = new Foo();
$foo->setLogger( new FileLogger() );

//note how we use the trait as a 'proxy' to call the Logger's log method on the Foo instance
$foo->log('my beautiful message');