如何传递 PDO 参数数组,同时仍指定其类型?

2022-08-30 22:13:02
$sql = "SELECT * FROM table WHERE id LIKE CONCAT('%', :id, '%')
LIMIT :limit1, :limit2";

我想仍然像这样使用数组输入:

$stmt->execute($array);

否则,我无法重用相同的方法来执行查询。

同时,除非像这样放入 :limit1 和 :limit2,否则它不起作用:

$stmt->bindParam(':limit1', $limit1, PDO::PARAM_INT);

我试图同时做这两件事,但它没有使用bindParams执行:

$stmt->bindParam(':limit2', $limit2, PDO::PARAM_INT);
$stmt->execute($array);

解决它的方法是什么?

我以为我可以扩展PDOStatement并添加一个新方法“bindLimit”或其他东西,但我无法弄清楚PDO使用什么内部方法将参数绑定到变量。


答案 1

如果关闭 默认设置 ,则它将起作用。我刚刚发现mysql的该设置默认处于打开状态,这意味着您实际上从未使用预准备语句,php在内部为您创建动态sql,为您引用值并替换占位符。丫的,一个主要的wtf。PDO::ATTR_EMULATE_PREPARES

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$stmt = $pdo->prepare($sql);
$stmt->execute(array(5)); //works!

由于性能原因,默认情况下会模拟准备工作。

另请参阅 PDO MySQL:使用 PDO::ATTR_EMULATE_PREPARES与否?


答案 2

PDOStatement::execute 的文档所述:

input_parameters

一个值数组,其元素数与正在执行的 SQL 语句中的绑定参数数一样多。所有值都被视为 。PDO::PARAM_STR

在大多数情况下,这完全没有被注意到,因为MySQL的隐式类型转换处理其余部分(但如果MySQL使用特别奇怪的连接字符集,它可能会导致一些不良行为,因为将数字字符串转换回其数值可能不会给出预期的结果)。

在你的例子中,MySQL正在尝试执行一个具有字符串参数的子句。虽然它可以尝试使用其隐式类型转换来解决这个问题,就像它在其他地方所做的那样,字符串出现在整数应该在的地方,它只是不打扰,而是哭泣。LIMIT

因此,您需要告诉PDO这些特定参数是整数。由于即使PHP也不知道它的变量是什么类型,我相信唯一的方法是像你一样直接将它们与PDOStatement::bindParamPDOStatement::bindValue绑定(尽管严格来说,将参数指定为给定PHP的简单转换,否则无能为力的类型系统足以使用)。$data_type(int)$variable

至于PDO用于将参数绑定到变量的内部方法,请查看really_register_bound_param()(不出所料,它没有公开给PHP,所以你会在C中有很多乐趣)。

祝你好运!


推荐