Getting raw SQL query string from PDO prepared statements

前端 未结 16 864
心在旅途
心在旅途 2020-11-22 06:56

Is there a way to get the raw SQL string executed when calling PDOStatement::execute() on a prepared statement? For debugging purposes this would be extremely useful.

16条回答
  •  长情又很酷
    2020-11-22 07:16

    You can extend PDOStatement class to capture the bounded variables and store them for later use. Then 2 methods may be added, one for variable sanitizing ( debugBindedVariables ) and another to print the query with those variables ( debugQuery ):

    class DebugPDOStatement extends \PDOStatement{
      private $bound_variables=array();
      protected $pdo;
    
      protected function __construct($pdo) {
        $this->pdo = $pdo;
      }
    
      public function bindValue($parameter, $value, $data_type=\PDO::PARAM_STR){
        $this->bound_variables[$parameter] = (object) array('type'=>$data_type, 'value'=>$value);
        return parent::bindValue($parameter, $value, $data_type);
      }
    
      public function bindParam($parameter, &$variable, $data_type=\PDO::PARAM_STR, $length=NULL , $driver_options=NULL){
        $this->bound_variables[$parameter] = (object) array('type'=>$data_type, 'value'=>&$variable);
        return parent::bindParam($parameter, $variable, $data_type, $length, $driver_options);
      }
    
      public function debugBindedVariables(){
        $vars=array();
    
        foreach($this->bound_variables as $key=>$val){
          $vars[$key] = $val->value;
    
          if($vars[$key]===NULL)
            continue;
    
          switch($val->type){
            case \PDO::PARAM_STR: $type = 'string'; break;
            case \PDO::PARAM_BOOL: $type = 'boolean'; break;
            case \PDO::PARAM_INT: $type = 'integer'; break;
            case \PDO::PARAM_NULL: $type = 'null'; break;
            default: $type = FALSE;
          }
    
          if($type !== FALSE)
            settype($vars[$key], $type);
        }
    
        if(is_numeric(key($vars)))
          ksort($vars);
    
        return $vars;
      }
    
      public function debugQuery(){
        $queryString = $this->queryString;
    
        $vars=$this->debugBindedVariables();
        $params_are_numeric=is_numeric(key($vars));
    
        foreach($vars as $key=>&$var){
          switch(gettype($var)){
            case 'string': $var = "'{$var}'"; break;
            case 'integer': $var = "{$var}"; break;
            case 'boolean': $var = $var ? 'TRUE' : 'FALSE'; break;
            case 'NULL': $var = 'NULL';
            default:
          }
        }
    
        if($params_are_numeric){
          $queryString = preg_replace_callback( '/\?/', function($match) use( &$vars) { return array_shift($vars); }, $queryString);
        }else{
          $queryString = strtr($queryString, $vars);
        }
    
        echo $queryString.PHP_EOL;
      }
    }
    
    
    class DebugPDO extends \PDO{
      public function __construct($dsn, $username="", $password="", $driver_options=array()) {
        $driver_options[\PDO::ATTR_STATEMENT_CLASS] = array('DebugPDOStatement', array($this));
        $driver_options[\PDO::ATTR_PERSISTENT] = FALSE;
        parent::__construct($dsn,$username,$password, $driver_options);
      }
    }
    

    And then you can use this inherited class for debugging purpouses.

    $dbh = new DebugPDO('mysql:host=localhost;dbname=test;','user','pass');
    
    $var='user_test';
    $sql=$dbh->prepare("SELECT user FROM users WHERE user = :test");
    $sql->bindValue(':test', $var, PDO::PARAM_STR);
    $sql->execute();
    
    $sql->debugQuery();
    print_r($sql->debugBindedVariables());
    

    Resulting in

    SELECT user FROM users WHERE user = 'user_test'

    Array ( [:test] => user_test )

提交回复
热议问题