假设users数据表为这样

如果我们要找sex为2,type为1的用户的信息,相应的sql语句就应该为

$query = User::where('type', 1)->where('sex', 2)->get();

如果此时,我们想打印sql语句,该如何做呢。。。

toSql()

在IlluminateDatabaseQueryBuilder,有一个toSql()方法,使用方式为:

$sql = User::where('type', 1)->where('sex', 2)->toSql();
dd($sql);

就会得到该Sql语句

但是此时sql语句中的变量都是问号,怎么获得完整的sql语句呢

getBindings()

在IlluminateDatabaseQueryBuilder中,还有一个getBindings()方法,可以获取sql语句中绑定的变量,使用方式为:

$bindings = User::where('type', 1)->where('sex', 2)->getBindings();
dd($bindings);

获得的变量以数组形式存在

只要将sql中的问号替换成变量就可以获得完整的sql语句了

$builer = User::where('type', 1)->where('sex', 2);
$sql = $builer->toSql();
$bindings = $builder->getBindings();
$tmp = str_replace('?', '%s', $sql);
$res = sprintf($tmp, ...$bindings);
dd($res);

结果为

为了以后方便使用,我们可以把它封装为一个方法,放到公共方法里

public function getSql($builder)
{
    return sprintf(str_replace('?', '%s', $builder->toSql(), ...$builder->getBindings()));
}

只需要在想打印sql的地方使用getSql()就可以了

$builder = User::where('sex', 2)->where('type', 1);
dd(getSql($buidler));

结果为
再进一步,能不能像toSql一样,直接在操作链后面接上方法呢

macro扩展

利用 macro 方法来扩展 Laravel 的基础类的功能,将getSql写入Builder

在AppProviders下新建一个SqlServiceProvider,并添加Builder的宏扩展在boot方法中

<?php

namespace App\Providers;

use Illuminate\Database\Query\Builder;
use Illuminate\Support\ServiceProviders;

class SqlServiceProviders extends ServiceProviders
{
    public function boot()
    {
        Builder::macro('getSql', function(){
            return sprintf(str_replace('?', '%s', $this->toSql(), ...$this->getBindings()));
        });
    }
    
    public function register()
    {
        //
    }
}

然后我们就可以在config/app.php中的服务提供者中加入

App\Providers\SqlServiceProvider::class

然后重载命名空间

 composer dumo-autoload

这时,我们只需要直接使用getSql()方法就可以获得sql语句了

$sql = User::where('type', 1)->where('sex', 2)->getSql();
dd($sql);