Laravel學習 - Eloquent\Builder與Query\Builder

在Laravel中出現了兩處針對數據庫的Builder,一時分不清楚。

Eloquent\Builder

Query\Builder


首先,確認Eloquent\Builder與Query\Builder是否是有繼承關係:

1/ 打印兩者之間的instanceof關係,發現並沒有關係

2/ 查看源碼:

 Eloquent\Builder的構造器方法中有一個注入參數QueryBuilder

/**
 * The base query builder instance.
 *
 * @var \Illuminate\Database\Query\Builder
 */
protected $query;

/**
 * Create a new Eloquent query builder instance.
 *
 * @param  \Illuminate\Database\Query\Builder  $query
 * @return void
 */
public function __construct(QueryBuilder $query)
{
   $this->query = $query;
}

 可見兩者之間並沒有繼承的關係,而是Eloquent\Builder採用了代理模式對Query\Builder進行了操作

/**
    * Dynamically handle calls into the query instance.
    *
    * @param  string  $method
    * @param  array  $parameters
    * @return mixed
    */
public function __call($method, $parameters)
{
    if ($method === 'macro') {
        $this->localMacros[$parameters[0]] = $parameters[1];

        return;
    }

    if (isset($this->localMacros[$method])) {
        array_unshift($parameters, $this);

        return $this->localMacros[$method](...$parameters);
    }

    if (isset(static::$macros[$method])) {
        if (static::$macros[$method] instanceof Closure) {
            return call_user_func_array(static::$macros[$method]->bindTo($this, static::class), $parameters);
        }

        return call_user_func_array(static::$macros[$method], $parameters);
    }

    if (method_exists($this->model, $scope = 'scope'.ucfirst($method))) {
        return $this->callScope([$this->model, $scope], $parameters);
    }

    if (in_array($method, $this->passthru)) {
        return $this->toBase()->{$method}(...$parameters);
    }

    $this->forwardCallTo($this->query, $method, $parameters);

    return $this;
}

 Eloquent\Builder中的__call方法,在最後也將當前類所有未能定位的方法全部forward到Query\Builder執行。


其次,如何使用Eloquent\Builder,又如何使用Query\Builder呢?

Laravel中既提供了實例的使用,也提供了快捷的Facade使用方法。如:

\Illuminate\Support\Facades\DB::table('user'); // --> object(Illuminate\Database\Query\Builder)

UserModel::query(); // --> object(Illuminate\Database\Eloquent\Builder)

可以看出,使用了Facades\DB得到的是Query\Builder,而在UserModel的query方法調用後得到的是Eloquent\Builder。

個人認爲:

1/ DB的方法固然方便,但是更多的將table的信息硬編碼,導致後期維護工作量大;

2/ Eloquent\Buidler代理了Query\Builder的方法,因此使用上也與DB的使用差別不大。

在日常的操作中,我們更多的是定義了Model操作類。在Mode類中明確指定了表的名稱:

/**
 * The table associated with the model.
 *
 * @var string
 */
protected $table;

所以,更建議採用Model的方式進行操作。


第三,Eloquent\Builder與Query\Builder得到的結果是否一致呢?

/**
 * Use Eloquent\Builder
 *
 */
$eloquentBuilderResult = User::query()->where('name', 'test')->first();
// var_dump($eloquentBuilderResult);
// object(\App\Models\User) {}

/**
 * Use Query\Builder
 */
$queryBuilderResult = DB::table('user')->where('name', 'test')->first();
// var_dump($queryBuilderResult);
// object(\stdClass) {}

因爲定義的User對象是繼承自\Illuminate\Database\Eloquent\Model(abstract),因此,所有的結果也均爲User對象類型。在這一點上,與Yii2的ActiveRecord(User::find)對象非常相似。

而Query\Builder是直接對錶數據進行操作,未與對象進行綁定映射關係等,所以在最後的結果呈現上,返回了stdClass的結果對象集。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章