You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP7.4中调用公共属性的链式方法后,如何回到调用类自身的链式方法?

解决PHP链式调用中从属性方法回到主类的问题

这个问题我之前也碰到过,核心原因是你链式调用到setId()的时候,返回的是FilterClient实例(因为trait BuilderClient里的setter返回的是self,也就是当前的FilterClient对象),而不是ClientList,所以没法直接接着调用ClientList的get()方法。下面给你几种可行的解决方案:

方案一:让FilterClient的setter返回ClientList实例

我们可以在FilterClient中保存一个ClientList的引用,然后修改所有setter方法的返回值为这个引用,这样调用完filter的方法后就能回到ClientList的上下文:

trait BuilderClient {
    protected $field1;
    public function setField1(int $field1): self {
        $this->field1 = new Field(); // 已封装
        return $this;
    }
}

// 假设Filter trait包含setId方法
trait Filter {
    protected $id;
    public function setId(string $id): self {
        $this->id = $id;
        return $this;
    }
}

class FilterClient{
    use BuilderClient;
    use Filter;
    
    private $clientList;

    // 接收ClientList实例
    public function setClientList(ClientList $clientList): self {
        $this->clientList = $clientList;
        return $this;
    }

    // 重写setter方法,返回ClientList而非自身
    public function setField1(int $field1): ClientList {
        parent::setField1($field1);
        return $this->clientList;
    }

    public function setId(string $id): ClientList {
        parent::setId($id);
        return $this->clientList;
    }
}

class ClientList {
    public $filter;
    public function getList(): array {
        // 构建列表逻辑
        return [];
    }
    
    function __construct() {
        $this->filter = new FilterClient();
        $this->filter->setClientList($this); // 将自身传递给filter
    }

    // 可选:添加一个filter()方法让链式调用更语义化
    public function filter(): FilterClient {
        return $this->filter;
    }
}

现在你可以这样链式调用:

// 两种写法都可行
$clientList = (new ClientList)->filter->setId('222')->getList();
// 或者更语义化的写法
$clientList = (new ClientList)->filter()->setId('222')->getList();

方案二:在ClientList中添加代理方法

这种方法不需要修改FilterClient,而是在ClientList中封装所有filter的操作,全程保持ClientList的上下文:

trait BuilderClient {
    protected $field1;
    public function setField1(int $field1): self {
        $this->field1 = new Field(); // 已封装
        return $this;
    }
}

trait Filter {
    protected $id;
    public function setId(string $id): self {
        $this->id = $id;
        return $this;
    }
}

class FilterClient{
    use BuilderClient;
    use Filter;
}

class ClientList {
    public $filter;
    public function getList(): array {
        // 构建列表逻辑
        return [];
    }
    
    function __construct() {
        $this->filter = new FilterClient();
    }

    // 代理filter的setId方法
    public function setFilterId(string $id): self {
        $this->filter->setId($id);
        return $this;
    }

    // 代理filter的setField1方法
    public function setFilterField1(int $field1): self {
        $this->filter->setField1($field1);
        return $this;
    }
}

链式调用写法:

$clientList = (new ClientList)->setFilterId('222')->getList();

这种方法的好处是ClientList和FilterClient的耦合度低,对外暴露的API更简洁;缺点是如果FilterClient有很多方法,需要编写大量代理方法。

方案三:使用Builder模式解耦

我们可以新增一个FilterBuilder类,专门处理filter的配置,最后通过end()方法回到ClientList:

trait BuilderClient {
    protected $field1;
    public function setField1(int $field1): self {
        $this->field1 = new Field(); // 已封装
        return $this;
    }
}

trait Filter {
    protected $id;
    public function setId(string $id): self {
        $this->id = $id;
        return $this;
    }
}

class FilterClient{
    use BuilderClient;
    use Filter;
}

class FilterBuilder {
    private $clientList;
    private $filter;

    public function __construct(ClientList $clientList) {
        $this->clientList = $clientList;
        $this->filter = $clientList->filter;
    }

    public function setId(string $id): self {
        $this->filter->setId($id);
        return $this;
    }

    public function setField1(int $field1): self {
        $this->filter->setField1($field1);
        return $this;
    }

    // 返回ClientList实例,结束filter配置
    public function end(): ClientList {
        return $this->clientList;
    }
}

class ClientList {
    public $filter;
    public function getList(): array {
        // 构建列表逻辑
        return [];
    }
    
    function __construct() {
        $this->filter = new FilterClient();
    }

    public function filter(): FilterBuilder {
        return new FilterBuilder($this);
    }
}

链式调用写法:

$clientList = (new ClientList)->filter()->setId('222')->end()->getList();

这种方法结构清晰,解耦效果好,适合filter配置项较多的场景。


内容的提问来源于stack exchange,提问作者Mechprogra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 20:22:48