Como extrair SQL bruto do Query Builder em PHP: 3 métodos funcionais

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

«Doutor, meu Query Builder está gerando algo estranho…»

\n

Situação familiar: você escreve uma consulta encadeada elegante no Query Builder, tem certeza de que tudo funciona perfeitamente, mas no final — ou um erro, ou dados incorretos. A primeira coisa que vem à mente de qualquer desenvolvedor PHP: «Mostre-me o que você está realmente gerando!».

\n

A pergunta «How do I get the query builder to output its raw SQL query as a string?» é uma das mais populares no Stack Overflow (milhares de visualizações e dezenas de respostas). E não é por acaso. A capacidade de obter rapidamente um SQL limpo é um superpoder que economiza horas de depuração.

\n

Neste artigo, abordaremos 3 métodos funcionais para frameworks PHP (Laravel, Doctrine, CakePHP), mostraremos exemplos reais de código e explicaremos quando usar cada método. Vamos lá!

\n\n

Por que isso é necessário? (Resumido e direto ao ponto)

\n
    \n
  • Depuração — entender por que a consulta retorna dados incorretos.
  • \n
  • Otimização — ver quais JOINs e WHEREs estão realmente sendo executados.
  • \n
  • Aprendizado — iniciantes muitas vezes não entendem como o Query Builder traduz métodos em SQL.
  • \n
  • Registro de logs — salvar a consulta bruta para auditoria ou repetição.
  • \n
\n

Pronto? Então vamos ao código!

\n\n

Método 1: Laravel Eloquent / Query Builder — clássico

\n

No Laravel, existem várias maneiras, mas a mais confiável é usar toSql() junto com getBindings(). Por que juntos? Porque toSql() mostra a consulta com placeholders ?, e sem substituir os valores, é inútil.

\n\n

Exemplo simples: SELECT com WHERE

\n
use App\\Models\\User;\n\n$query = User::where('email', 'like', '%@gmail.com')\n             ->where('active', 1)\n             ->orderBy('created_at', 'desc');\n\n// Obtém o SQL com placeholders\n$sql = $query->toSql();\n$bindings = $query->getBindings();\n\n// Monta tudo em um formato legível\n$fullSql = vsprintf(str_replace('?', '%s', $sql), $bindings);\n\necho $fullSql;\n// Resultado:\n// SELECT * FROM users WHERE email LIKE '%@gmail.com' AND active = 1 ORDER BY created_at DESC
\n

Importante: vsprintf não é uma solução universal. Para tipos de dados complexos (por exemplo, NULL ou arrays), é melhor usar Str::replaceArray() ou o pacote laravel-query-builder-debug.

\n\n

Variante avançada: com join e whereIn

\n
$query = DB::table('orders')\n    ->join('users', 'orders.user_id', '=', 'users.id')\n    ->whereIn('orders.status', ['pending', 'processing'])\n    ->where('orders.total', '>', 100)\n    ->select('orders.*', 'users.name');\n\n$bindings = $query->getBindings();\n$sql = $query->toSql();\n\n// Formata de forma elegante\n$fullSql = preg_replace_array('/\\?/', $bindings, $sql);\necho $fullSql;\n// SELECT orders.*, users.name FROM orders INNER JOIN users ON orders.user_id = users.id WHERE orders.status IN ('pending', 'processing') AND orders.total > 100
\n

Dica: Use preg_replace_array() — é mais seguro que vsprintf, especialmente quando os dados contêm o caractere %.

\n\n

Método 2: Doctrine DBAL — para quem gosta de rigor

\n

O Doctrine Query Builder (frequentemente usado no Symfony) é um bicho mais complicado. Aqui não há um toSql() pronto, mas existem getSQL() e getParameters(). Além disso, é necessário considerar os tipos dos parâmetros.

\n\n

Exemplo básico

\n
use Doctrine\\DBAL\\Connection;\nuse Doctrine\\DBAL\\Query\\QueryBuilder;\n\n/** @var Connection $connection */\n$queryBuilder = $connection->createQueryBuilder();\n$queryBuilder\n    ->select('p.*', 'c.name as category_name')\n    ->from('products', 'p')\n    ->join('p', 'categories', 'c', 'p.category_id = c.id')\n    ->where('p.price > :minPrice')\n    ->andWhere('p.sto                

Blogs

Book Recommendations