利用 __call($method, $args) 攔截不存在的方法調用,將方法名映射為 SQL 子句鍵名,參數存入屬性,返回 $this 實現鏈式調用。比顯式定義每個方法更靈活,易於擴展。
class DbBuilder {
// 定義支援的鏈式方法 (對應 SQL 子句)
protected $clauses = [
'field' => '',
'where' => '',
'order' => '',
'limit' => '',
'group' => '',
'having' => '',
];
public function __call(string $method, array $args) {
$method = strtolower($method);
if (isset($this->clauses[$method])) {
$this->clauses[$method] = $args[0] ?? '';
return $this;
}
throw new BadMethodCallException("未支援的方法: $method");
}
public function select(): string {
$sql = "SELECT {$this->clauses['field']} FROM `test` ";
$sql .= "{$this->clauses['where']} ";
$sql .= "{$this->clauses['group']} ";
$sql .= "{$this->clauses['having']} ";
$sql .= "{$this->clauses['order']} ";
$sql .= "{$this->clauses['limit']}";
return trim(preg_replace('/\s+/', ' ', $sql));
}
}
// 使用
$db = new DbBuilder();
echo $db->field('name, sex, address')
->where('name = "gongwen"')
->limit('1')
->select();
// SELECT name, sex, address FROM `test` WHERE name = "gongwen" LIMIT 1
isset($this->clauses[$method]) 防止任意屬性寫入。$args[0] ?? '' 兼容無參調用。'join' => '' 即支援 ->join('...'),無需新增方法。| 維度 | 顯式方法 | __call 動態 |
|---|---|---|
| 代碼量 | 多 (每個子句一個方法) | 少 (統一攔截) |
| IDE 提示 | 完美支援 | 無 (需 @method 註解) |
| 擴展新子句 | 新增方法 | 修改白名單陣列 |
| 參數驗證/轉換 | 靈活 (每個方法獨立) | 統一處理 (需額外邏輯) |
| 效能 | 極快 (直接調用) | 微弱開銷 (魔術方法查找) |
__call 動態支援。@method 註解讓 PHPStorm 識別動態方法:@method self where(string $cond)