用 PHP 連結的方法

方法連結是 Martin Fowler 的書“ Domain Specific Languages”中 解釋的一種技術。方法連結總結為

使修飾符方法返回主機物件,以便可以在單個表示式中呼叫多個修飾符

考慮這段非連結/常規程式碼(從前面提到的書中移植到 PHP)

$hardDrive = new HardDrive;
$hardDrive->setCapacity(150);
$hardDrive->external();
$hardDrive->setSpeed(7200);

方法連結允許你以更緊湊的方式編寫上述語句:

$hardDrive = (new HardDrive)
    ->setCapacity(150)
    ->external()
    ->setSpeed(7200);

你需要做的就是在你想要連結的方法中使用 return $this

class HardDrive {
    protected $isExternal = false;
    protected $capacity = 0;
    protected $speed = 0;

    public function external($isExternal = true) {
        $this->isExternal = $isExternal;        
        return $this; // returns the current class instance to allow method chaining
    }

    public function setCapacity($capacity) {
        $this->capacity = $capacity;        
        return $this; // returns the current class instance to allow method chaining
    }

    public function setSpeed($speed) {
        $this->speed = $speed;        
        return $this; // returns the current class instance to allow method chaining
    }
}

何時使用它

使用方法鏈的主要用例是構建內部域特定語言。方法鏈是一個構建塊表達的建設者流利的介面但它並不是那些同義詞 。方法連結只能啟用那些。引用福勒:

我也注意到了一個常見的誤解 - 許多人似乎將流暢的介面等同於 Method Chaining。當然連結是一種常用的技術,可以使用流暢的介面,但真正的流暢性遠不止於此。

話雖如此,使用 Method Chaining 只是為了避免編寫宿主物件被許多人認為是程式碼味道 。它會產生不明顯的 API,尤其是在與非連結 API 混合時。

補充說明

命令查詢分離

命令查詢分離是 Bertrand Meyer 提出的設計原則 。它宣告變異狀態( 命令 )的方法不應該返回任何東西,而返回某些東西( 查詢 )的方法不應該改變狀態。這使得更容易推理系統。方法連結違反了這個原則,因為我們正在改變狀態返回一些東西。

getter

當使用實現方法連結的類時,在呼叫 getter 方法時要特別注意(即返回 $this 之外的其他方法)。由於 getter 必須返回以外的值比 $this,連結的附加方法到 getter 使得呼叫的操作得到的值,而不是原始物件上。雖然鏈式 getter 有一些用例,但它們可能會降低程式碼的可讀性。

得墨忒耳定律及對測試的影響

方法如上所述連結不違反得墨忒耳定律 。它也不會影響測試。那是因為我們正在返回主機例項,而不是一些協作者。這是一種常見的錯誤觀念,源於人們將方法連結與 Fluent InterfacesExpression Builders 混淆。只有當 Method Chaining 返回其他物件而不是主機物件時,才會違反 Demeter 法並在測試中結束模擬測試。