用 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 法并在测试中结束模拟测试。