您不能将查询参数用于表达式。参数仅代替单个标量值。所以不是 PDO 不能绑定字符串变量,而是你的字符串“sum+5”将被计算为一个整数,而不是一个 SQL 表达式。MySQL 对“sum+5”的整数值的想法是 0。
这不是 PDO 的限制,它是 SQL 的定义方式。无论客户端编程语言或 RDBMS 品牌如何,它都将以相同的方式工作。这是开发人员学习 SQL 的常见障碍。 参数不是字符串插值。 字符串插值发生在prepare()
. 在解析 SQL 之后,在execute()
. 参数值不能强制重新解析 SQL,因此不能在查询中引入额外的表达式语法。这就是它防止 SQL 注入的方式。
如果您的输入字符串有时可能是表达式,而有时可能是常量值,那么您的情况很复杂。您可以做的最好的事情是编写代码来测试您的输入字符串并进行字符串插值或参数化。
您可以将对象而不是字符串传递给数据库查询方法(PHP 是一种松散类型的语言,这很容易)。如果该值是一个对象,则将其插入到查询字符串中。如果方法参数是标量,则使用参数。
function my_update_method($args) {
$params = array();
$query = "UPDATE mytable SET ";
foreach ($args as $column => $value) {
if ($value instanceof SQLTerm)
{
$query .= "`" . $column . "` = " . $value; /* calls object's __toString() method */
} else {
$query .= "`" . $column . "` = ?";
$params[] = $value;
}
}
$updatenum = $db->prepare($query);
$updatenum->execute($params);
}
SQLTerm 类只是一个字符串的包装器,它的唯一目的是成为一个对象而不是一个字符串,因此我们可以判断一个值何时是要参数化的字符串标量,还是不能参数化的表达式。
class SQLTerm
{
protected $string;
public function __construct($string) {
$this->string = $string;
}
public function __toString() {
return $this->string;
}
}
这意味着调用者负责以一种避免 SQL 注入风险的方式创建 SQLTerm 对象。