PHP, PDO, last query, bindParam

2019-06-05 08:16发布

问题:

I would like to have the last query (for debugging purposes) from the PDOStatement. But I can't override the bindParam and bindValue methods. When I tried the code below, I got:

Fatal error: Default value for parameters with a class type hint can only be NULL

Then I replaced the PDO::PARAM_STR to null in the parameter list of bindParam/bindValue, so I got:

Strict Standards: Declaration of DBStatement::bindParam() should be compatible with that of PDOStatement::bindParam()

I then deleted int before the $data_type parameter and set the default value to PDO::PARAM_STR. Then I got:

Strict Standards: Declaration of DBStatement::bindParam() should be compatible with that of PDOStatement::bindParam() in D:\www\pdotest.php on line 73

(interestingly, the bindValue is okay now).

So, what can I do now?

class DBConnection extends PDO
{
    public function __construct($dsn, $username = null, $password = null, $driver_options = array())
    {
        parent::__construct($dsn, $username, $password, $driver_options);

        $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DBStatement', array($this)));
        $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
}

class DBException extends PDOException
{
    private $query_string;
    private $parameters;

    public function __construct($message = '', $code = 0, $previous = null, $query_string = '', $parameters = array())
    {
        parent::__construct($message, $code, $previous);        

        $this->query_string = $query_string;
        $this->parameters = $parameters;
    }

    public function getQueryString()
    {
        return $this->query_string;
    }   

    public function getParameters()
    {
        return $this->parameters;
    }
}

class DBStatement extends PDOStatement
{
    private $conn;
    private $parameters = array();

    protected function __construct($conn)
    {
        $this->conn = $conn;
    }

    public function bindParam($parameter, &$variable, int $data_type = PDO::PARAM_STR, int $length = null, $driver_options = null)
    {
        $this->parameters[$parameter] = $variable;

        parent::bindParam($parameter, $variable, $data_type, $length, $driver_options);
    }

    public function bindValue($parameter, $value, int $data_type = PDO::PARAM_STR)
    {
        $this->parameters[$parameter] = $value;

        parent::bindValue($parameter, $value, $data_type);
    }

    public function execute($input_parameters = null)
    {
        try
        {
            parent::execute($input_parameters);
        }
        catch (PDOException $e)
        {
            throw new DBException($e->getMessage(), $e->getCode(), $e->getPrevious(), $this->queryString, $this->parameters);
        }
    }
}

$id = 1;

try
{
    $conn = new DBConnection('mysql:host=localhost;dbname=test', 'root', '');
    $stmt = $conn->prepare('select * from foo where id = :id');
    $stmt->bindParam(':id', $id);
    $stmt->execute();
}
catch (DBException $e)
{
    echo "Query string was: ".$e->getQueryString()."\n";
    echo "Parameters was: ".print_r($e->getParameters(), true);
}

I also recieve te following when I throw a DBException (because of $code parameter):

Notice: A non well formed numeric value encountered in D:\www\pdotest.php on line 21

回答1:

Don't need to use the "int" type of the $data_type variable, then it works.

public function bindParam($parameter, &$variable, $data_type = PDO::PARAM_STR, $length = null, $driver_options = null)
{
    $this->parameters[$parameter] = $variable;

    parent::bindParam($parameter, $variable, $data_type, $length, $driver_options);
}

public function bindValue($parameter, $value, $data_type = PDO::PARAM_STR)
{
    $this->parameters[$parameter] = $value;

    parent::bindValue($parameter, $value, $data_type);
}


回答2:

The Notice you are receiving seems to be due to this unresolved php bug. I would change the overridden bindParam and bindValue so that they are compatible with the parent's declaration. If you want to set your own default parameter values you can do so in the overridden methods. Lastly, I'd simply change the construction of the exception to omit the code:

throw new DBException($e->getMessage(), NULL, $e->getPrevious(), $this->queryString, $this->parameters);