__call(string $name, array $arguments): mixed 是 PHP 5+ 引入的魔術方法,當調用不可訪問的實例方法(不存在、protected/private)時自動觸發。
雙胞胎方法:__callStatic() 處理靜態方法調用。
class MethodTest {
public function __call($name, $arguments) {
echo "調用了不存在的方法: $name\n";
echo "參數: " . implode(', ', $arguments) . "\n";
return $this; // 支持鏈式調用的關鍵
}
}
$obj = new MethodTest();
$obj->runTest('in object context');
// 輸出:
// 調用了不存在的方法: runTest
// 參數: in object context
原始碼邏輯簡化版 (think/Model.php):
class Model {
protected $options = [];
public function __call($method, $args) {
$method = strtolower($method);
// 1. 連貫操作:field、where、order、limit、page 等
if (in_array($method, ['field','table','where','order','limit','page','alias','having','group','lock','distinct'], true)) {
$this->options[$method] = $args[0] ?? true;
return $this; // 返回 $this 實現鏈式
}
// 2. 統計查詢:count、sum、min、max、avg
if (in_array($method, ['count','sum','min','max','avg'], true)) {
$field = $args[0] ?? '*';
return $this->getField(strtoupper($method) . "($field) AS tp_$method");
}
// 3. 動態獲取器:getBy字段名
if (str_starts_with($method, 'getby')) {
$field = lcfirst(substr($method, 5)); // 駝峰轉下劃線邏輯簡化
$where = [$field => $args[0]];
return $this->where($where)->find();
}
throw new \BadMethodCallException("方法 $method 不存在");
}
// 簡化的查詢執行入口
public function select() { /* 執行 SELECT ... */ return []; }
public function find() { /* 執行 SELECT ... LIMIT 1 */ return null; }
public function getField($field) { /* 執行 SELECT $field */ return null; }
}
$model = new Model();
// 等價於: SELECT * FROM table WHERE status=1 ORDER BY id DESC LIMIT 10
$model->field('id,name')
->where(['status' => 1])
->order('id DESC')
->limit(10)
->select();
// 統計查詢
$total = $model->where(['status'=>1])->count();
// 動態獲取
$user = $model->getByEmail('test@example.com');
$this$optionsselect/find/count) 觸發真實 SQL 構建執行| 優點 | 缺點 |
|---|---|
| API 極其流暢,閱讀如自然語言 | IDE 無法自動提示虛擬方法 |
| 減少參數傳遞,代碼極簡 | 調試困難,堆棧信息不直觀 |
| 動態擴展性強 | 拼寫錯誤運行時才發現 |
| 實現 DSL (領域特定語言) | 性能略有損耗 (微乎其微) |
/**
* @method static $this where(array $condition)
* @method static $this field(string|array $fields)
* @method static $this limit(int|string $limit)
* @method static $this order(string $order)
* @method mixed getByEmail(string $email)
*/
__callpublic function __call(string $name, array $args): self|mixed__call 是 PHP 實現動態代理、流式 API、DSL 的核心機制。ThinkPHP 的 Model 鏈式調用是教科書級應用。合理使用可極大提升代碼可讀性,但需權衡 IDE 支持與調試便利性,建議配合註解與靜態分析工具 (PHPStan/Psalm) 使用。