鏈式調用通過方法返回 $this 實現連續調用,極大提升代碼可讀性與編寫體驗,是現代 PHP 框架(Laravel Query Builder、ThinkPHP Model、Doctrine QB)的核心設計模式。本文通過構建一個 SQL 查詢構建器,詳細演示鏈式調用的實現原理與擴展技巧。
class Builder {
public function method1() { /* ... */ return $this; }
public function method2() { /* ... */ return $this; }
}
// 使用
$builder->method1()->method2()->method3();
關鍵點:每個鏈式方法必須 return $this,最終由終結方法(如 get()、toSql())返回實際結果。
<?php
class SqlBuilder {
private $sql = [
'select' => '*',
'from' => '',
'where' => '',
'order' => '',
'limit' => '',
'params' => [] // 參數綁定,防注入
];
// SELECT 字段
public function select(string $fields = '*'): self {
$this->sql['select'] = $fields;
return $this;
}
// FROM 表
public function from(string $table): self {
$this->sql['from'] = "FROM {$table}";
return $this;
}
// WHERE 條件(支持參數綁定)
public function where(string $column, $operator = null, $value = null): self {
// 重載:where('id', 1) / where('id', '>', 1) / where('status', '=', 1, 'AND')
if (func_num_args() === 2) {
$value = $operator;
$operator = '=';
}
$logic = func_num_args() === 4 ? func_get_arg(3) : 'AND';
$placeholder = ':' . preg_replace('/[^a-z0-9_]/i', '', $column);
$condition = "{$column} {$operator} {$placeholder}";
if ($this->sql['where']) {
$this->sql['where'] .= " {$logic} {$condition}";
} else {
$this->sql['where'] = "WHERE {$condition}";
}
$this->sql['params'][$placeholder] = $value;
return $this;
}
// OR WHERE 簡寫
public function orWhere(string $column, $operator = null, $value = null): self {
return $this->where($column, $operator, $value, 'OR');
}
// ORDER BY
public function orderBy(string $column, string $direction = 'ASC'): self {
$this->sql['order'] = "ORDER BY {$column} " . strtoupper($direction);
return $this;
}
// LIMIT / OFFSET
public function limit(int $count, int $offset = 0): self {
$this->sql['limit'] = $offset > 0
? "LIMIT {$offset}, {$count}"
: "LIMIT {$count}";
return $this;
}
// 獲取最終 SQL(調試用)
public function toSql(): string {
$parts = array_filter($this->sql, function($k) { return $k !== 'params'; }, ARRAY_FILTER_USE_KEY);
return implode(' ', $parts);
}
// 獲取綁定參數
public function getBindings(): array {
return $this->sql['params'];
}
// 執行查詢(需注入 PDO)
public function get(PDO $pdo): array {
$stmt = $pdo->prepare($this->toSql());
$stmt->execute($this->getBindings());
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 重置構建器(復用實例)
public function reset(): self {
$this->sql = [
'select' => '*', 'from' => '', 'where' => '',
'order' => '', 'limit' => '', 'params' => []
];
return $this;
}
}
// 使用示例
$builder = new SqlBuilder();
$users = $builder->select('id, name, email')
->from('users')
->where('status', 1)
->where('role', '!=', 'banned')
->orWhere('is_admin', 1)
->orderBy('created_at', 'DESC')
->limit(10)
->get($pdo);
echo $builder->toSql();
// SELECT id, name, email FROM users WHERE status = :status AND role != :role OR is_admin = :is_admin ORDER BY created_at DESC LIMIT 10
?>
Model::where()->field()->order()->limit()->select(),終結方法 select/find/get 觸發查詢執行DB::table()->where()->orderBy()->limit()->get(),底層 Illuminate\Database\Query\Builder 實現 __call 動態代理Model,查詢構建器方法代理到 newQuery() 返回的 Builder 實例靜態方法無 $this,需返回 新實例 或使用 靜態屬性存儲狀態(非線程安全):
class StaticBuilder {
private static $instance;
private $data = [];
public static function create(): self {
self::$instance = new self();
return self::$instance;
}
public function set(string $key, $value): self {
$this->data[$key] = $value;
return $this;
}
public function getData(): array {
$result = $this->data;
self::$instance = null; // 用後重置
return $result;
}
}
// 使用
$result = StaticBuilder::create()->set('a', 1)->set('b', 2)->getData();
注意:靜態鏈式調用在併發環境下有狀態污染風險,生產環境建議使用實例模式或無狀態函數式風格。
public function scopeActive(self $query): self {
return $query->where('status', 1);
}
// 使用
User::query()->active()->get(); // ThinkPHP/Laravel 支持
public function limit(int $count, int $offset = 0): self {
if ($count <= 0) throw new \InvalidArgumentException('Limit must be positive');
if ($offset < 0) throw new \InvalidArgumentException('Offset cannot be negative');
// ...
}
構建器實例可復用,但需提供 reset() 或 newQuery() 確保狀態隔離。
鏈式調用本質是 方法返回對象自身($this),配合 終結方法觸發執行 的流式接口模式。核心優勢:
掌握此模式可自行構建查詢構建器、HTTP 客戶端、配置構建器、報表生成器等流式 API。