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
相关产品推荐
相关产品推荐

