php 如何用LIMIT子句传递PDO参数数组?

oxcyiej7  于 2023-10-15  发布在  PHP
关注(0)|答案(3)|浏览(124)
$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);

有什么办法可以绕过它?
我想我可以扩展PDO语句并添加一个新方法“bindLimit”或其他东西,但我不知道PDO使用什么内部方法将参数绑定到变量。

p5fdfcr1

p5fdfcr11#

如果你关闭PDO::ATTR_EMULATE_PREPARES的默认设置,那么它将工作。我刚发现mysql默认是开启这个设置的,这意味着你从来没有真正使用过预处理语句,php在内部为你创建动态sql,为你引用值并替换占位符。是啊,一个主要的WTF。

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

由于性能原因,默认情况下会模拟准备。
参见PDO MySQL: Use PDO::ATTR_EMULATE_PREPARES or not?

nafvub8i

nafvub8i2#

PDOStatement::execute的文档所述:

  • input_parameters*

一个值数组,其元素数与正在执行的SQL语句中的绑定参数数一样多。所有值均视为PDO::PARAM_STR
在大多数情况下,这完全没有被注意到,因为MySQL的implicit type conversion处理了其余部分(但如果MySQL使用特别奇怪的连接字符集,它可能会导致一些不希望的行为,因为将数字字符串转换回其数值可能不会给予预期的结果)。
在本例中,MySQL试图执行一个具有字符串参数的LIMIT子句。虽然它可以尝试使用隐式类型转换来解决这个问题,就像它在其他任何地方出现字符串的地方一样,它只是不麻烦,而是哭着跑了。
所以,你需要告诉PDO这些特定的参数是整数。由于PHP也不知道它的变量是什么类型,我相信唯一的方法就是直接将它们与PDOStatement::bindParamPDOStatement::bindValue绑定在一起(尽管指定$data_type参数并不是 * 严格 * 必要的,因为$variable的简单(int)转换给了PHP的其他类型系统足够的工作)。
至于PDO用于将参数绑定到变量的内部方法,请看一下really_register_bound_param()(毫不奇怪,它没有暴露于PHP,因此您将在C中获得很多乐趣)。
祝你好运!

jc3wubiy

jc3wubiy3#

当限制值不是用户输入时,为什么要绑定它们?

$start = 0;
$limit = 20;
$sql = "SELECT * FROM table WHERE id LIKE CONCAT('%', :id, '%')
    LIMIT $start, $limit";

即使$start$limit是由用户输入确定的,比如说从$_GET,你也可以用is_int()来测试这个值。

相关问题