【问题标题】:Get raw sql from Phalcon query builder从 Phalcon 查询生成器获取原始 sql
【发布时间】:2025-12-04 19:50:01
【问题描述】:

是否可以从 Phalcon 中的查询构建器实例中提取原始 sql 查询?像这样?

$queryBuilder = new Phalcon\Mvc\Model\Query\Builder();
$queryBuilder
    ->from(…)
    ->where(…);

$rawSql = $queryBuilder->hypotheticalGetRawQueryMethod();

【问题讨论】:

    标签: phalcon


    【解决方案1】:

    您可以在 DbAdapter 上使用 getRealSqlStatement()(或类似的函数名称)。见http://docs.phalconphp.com/en/latest/api/Phalcon_Db_Adapter.html

    根据文档,您可以通过这种方式获得生成的 sql 查询。

    或者等一下,这可能不适用于查询构建器。否则,您可以设置低级查询日志记录:http://docs.phalconphp.com/en/latest/reference/models.html#logging-low-level-sql-statements

    【讨论】:

      【解决方案2】:

      通过错误和尝试,以下似乎有效。如果有人能确认是否有更好的方法,那就太好了。

      $queryBuilder = new Builder();
      $queryBuilder->from(…)->where(…);
      
      $intermediate = $queryBuilder->getQuery()->parse();
      $dialect      = DI::getDefault()->get('db')->getDialect();
      $sql          = $dialect->select($intermediate);
      

      编辑:从 2.0.3 开始,您可以非常简单地做到这一点,详情请参阅 comment

      $modelsManager->createBuilder()
          ->from('Some\Robots')
          ->getQuery()
          ->getSql()
      

      【讨论】:

        【解决方案3】:
        $db = Phalcon\DI::getDefault()->getDb();
        $sql = $db->getSQLStatement();
        $vars = $db->getSQLVariables();
        if ($vars) {
            $keys = array();
            $values = array();
            foreach ($vars as $placeHolder=>$var) {
                // fill array of placeholders
                if (is_string($placeHolder)) {
                    $keys[] = '/:'.ltrim($placeHolder, ':').'/';
                } else {
                    $keys[] = '/[?]/';
                }
                // fill array of values
                // It makes sense to use RawValue only in INSERT and UPDATE queries and only as values
                // in all other cases it will be inserted as a quoted string
                if ((strpos($sql, 'INSERT') === 0 || strpos($sql, 'UPDATE') === 0) && $var instanceof \Phalcon\Db\RawValue) {
                    $var = $var->getValue();
                } elseif (is_null($var)) {
                    $var = 'NULL';
                } elseif (is_numeric($var)) {
                    $var = $var;
                } else {
                    $var = '"'.$var.'"';
                }
                $values[] = $var;
            }
            $sql = preg_replace($keys, $values, $sql, 1);
        }
        

        更多你可以阅读there

        【讨论】:

          【解决方案4】:

          如果您使用的是查询生成器,那么如下所示,getPhql 函数可以根据 phalcon 3.4.4 版本达到目的。

          
              $queryBuilder = new Builder();
              $queryBuilder->from(…)->where(…)->getQuery();
              $queryBuilder->getPhql();
          
          

          【讨论】:

            【解决方案5】:
            if (!function_exists("getParsedBuilderQuery")) {
                /**
                 * @param \Phalcon\Mvc\Model\Query\BuilderInterface $builder
                 *
                 * @return null|string|string[]
                 */
                function getParsedBuilderQuery (\Phalcon\Mvc\Model\Query\BuilderInterface $builder) {
                    $dialect = Phalcon\Di::getDefault()->get('db')->getDialect();
                    $sql = $dialect->select($builder->getQuery()->parse());
            
                    foreach ($builder->getQuery()->getBindParams() as $key => $value) {
                        // For strings work fine. You can add other types below
                        $sql = preg_replace("/:?\s?($key)\s?:?/","'$value'",$sql);
                    }
                    return $sql;
                }
            }
            

            我用来调试的简单函数。

            【讨论】:

              【解决方案6】:

              以下是常见的解决方案:

              $result = $modelsManager->createBuilder()
                          ->from(Foo::class)
                          ->where('slug = :bar:', ['bar' => "some-slug"])
                          ->getQuery()
                          ->getSql();
              

              但您可能不会期望看到没有值的查询,例如:

              die(print_r($result, true));
              
              Array
              (
                  [sql] => SELECT `foo`.`id`, `foo`.`slug` FROM `foo` WHERE `foo`.`slug` = :bar
                  [bind] => Array
                      (
                          [bar] => some-slug
                      )
              
                  [bindTypes] => 
              )
              

              所以,这个简单的代码可能很有用:

              public static function toSql(\Phalcon\Mvc\Model\Query\BuilderInterface $builder) : string
                  {
                      $data = $builder->getQuery()->getSql();
              
                      ['sql' => $sql, 'bind' => $binds, 'bindTypes' => $bindTypes] = $data;
              
                      $finalSql = $sql;
                      foreach ($binds as $name => $value) {
                          $formattedValue = $value;
              
                          if (\is_object($value)) {
                              $formattedValue = (string)$value;
                          }
              
                          if (\is_string($formattedValue)) {
                              $formattedValue = sprintf("'%s'", $formattedValue);
                          }
                          $finalSql = str_replace(":$name", $formattedValue, $finalSql);
                      }
              
                      return $finalSql;
                  }
              

              【讨论】: