Add PDO::PARAM_INT
or PDO::PARAM_STR
have any meaning in Mysql query?
$sql = 'SELECT TagId FROM tagthread WHERE ThreadId = :ThreadId';
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':ThreadId', $threadid, PDO::PARAM_INT);
$stmt->execute();
Yes, use it.
I did a few tests (with PDO::ATTR_EMULATE_PREPARES false
) and I found out that the quotes around the values will be different.
When you bind an integer value with PARAM_INT
there will be no quotes in the query (A string value with PARAM_INT has quotes). If you bind an integer value with PDO::PARAM_STR
there will be quotes and mysql has to cast to integer.
Examples:
$stmt->bindParam(':ThreadId', $threadid, PDO::PARAM_INT);
$threadid = 123;
// SELECT TagId FROM tagthread WHERE ThreadId = 123
$threadid = '123test';
// SELECT TagId FROM tagthread WHERE ThreadId = '123test'
// mysql will cast 123test to 123
EDIT:
I further tested and read on that topic. Conclusion: Implicit casting is dangerous and can lead to unexpected results.
Read more on that here. Another disadvantage to always use PDO::PARAM_STR
is the performance. Read more on performance Disadvantages of quoting integers in a Mysql query?
So if your column is of type [TINY|SMALL|MEDIUM|BIG]INT
than use PARAM_INT
. And in case it is a LIMIT
clause than cast to integer if the variable type in PHP is not integer.
Edit: Depends! See Your Common Sense comment below.
If the value is a integer it should be treated as an integer. Apply this with as many datatypes as possible.
If you don't set the Attribute of PDO::ATTR_EMULATE_PREPARES to false, you will get a nasty error.
Solid example:
$stmt = $dbh->prepare("SELECT * FROM table123 WHERE raw_field = :field LIMIT 1 OFFSET :offset;");
$stmt->bindParam(':field', $field);
$stmt->bindParam(':offset', $offset);
if ($map_stmt->execute())
{
$data = stmt->fetch(PDO::FETCH_ASSOC);
}
else
{
echo 'Error :';
echo '<pre>';
print_r($map_stmt->errorInfo());
print_r($map_stmt->debugDumpParams());
echo '</pre>';
}
Will return back a nasty error containing:
Error Code: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''0'' at line 1
Query: SELECT * FROM table123 WHERE raw_field = 'home' LIMIT 1 OFFSET '0'
Useless you treat it as an integer, and it will remove the string (e.g.: ' ').
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
In a nutshell:
You choose! Strict data or not..
I cannot tell for all the drivers supported by PDO, but for mysql it's ok not to use PDO::PARAM_INT
most of time.
Therefore, it makes no sense to bloat your code with numerous bindParam
calls. As a rule, just send your variables directly into execute()
:
$sql = 'SELECT TagId FROM tagthread WHERE ThreadId = ?';
$stmt = $this->db->prepare($sql);
$stmt->execute([$threadid]);
Here your $threadid
variable will be silently bound as a string, but it will make not a single problem for mysql to compare it with integer value stored in database. In reality, everyone does it this way and never has any problem.
The problem with string type bindnig in LIMIT
clause can be easily solved by switfhing the emulation mode OFF.
Note that PDO::PARAM_INT
doesn't cast your value. Means if you're trying to bind a string type value using this mode, it will be bound as a string nevertheless, even if you explicitly set type to PDO::PARAM_INT
. This mode will be actually applied only for integer values.
There are few edge cases where you may want to bind an integer explicitly though:
BIGINT
or BOOLEAN
that require an operand of exact type to be bound (note that in order to bind a BIGINT value with PDO::PARAM_INT you need a mysqlnd-based installation).All other issues are common for the loose typing and neither mysql nor PDO binding has any special effect in them.
Also, to avoid possible problems you should choose right column types for your data. Say, for big integers you should use BIGINT
, while for any price-like data it have to be DECIMAL
. And there will be not a single issue with comparison.