促進水平程式碼重用的特性

假設我們有一個用於記錄的介面:

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');