我很好奇是否有可能使用PDO将值数组绑定到占位符。这里的用例试图传递一个值数组,以便与IN()条件一起使用。
我希望能够这样做:
<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>
并让PDO绑定并引用数组中的所有值。
目前我正在做:
<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
$val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$in.')'
);
$stmt->execute();
?>
这当然是工作,但只是想知道是否有一个内置的解决方案,我错过了?
在经历了同样的问题之后,我采用了一个更简单的解决方案(尽管仍然没有PDO::PARAM_ARRAY那样优雅):
给定数组$ids = array(2,4,32):
$newparams = array();
foreach ($ids as $n => $val){ $newparams[] = ":id_$n"; }
try {
$stmt = $conn->prepare("DELETE FROM $table WHERE ($table.id IN (" . implode(", ",$newparams). "))");
foreach ($ids as $n => $val){
$stmt->bindParam(":id_$n", intval($val), PDO::PARAM_INT);
}
$stmt->execute();
... 等等
所以如果你正在使用一个混合值数组,你将需要更多的代码来测试你的值,然后再分配类型参数:
// inside second foreach..
$valuevar = (is_float($val) ? floatval($val) : is_int($val) ? intval($val) : is_string($val) ? strval($val) : $val );
$stmt->bindParam(":id_$n", $valuevar, (is_int($val) ? PDO::PARAM_INT : is_string($val) ? PDO::PARAM_STR : NULL ));
但是我还没有测试过这个。
因为我做了很多动态查询,所以这是我做的一个超级简单的helper函数。
public static function bindParamArray($prefix, $values, &$bindArray)
{
$str = "";
foreach($values as $index => $value){
$str .= ":".$prefix.$index.",";
$bindArray[$prefix.$index] = $value;
}
return rtrim($str,",");
}
像这样使用它:
$bindString = helper::bindParamArray("id", $_GET['ids'], $bindArray);
$userConditions .= " AND users.id IN($bindString)";
返回一个字符串:id1,:id2,:id3,并更新你的$bindArray绑定,当你需要运行你的查询时。简单!
在PDO中不可能使用这样的数组。
你需要为每个值构建一个带参数的字符串(或使用?),例如:
: an_array_0: an_array_1: an_array_2 an_array_3,:: an_array_5 an_array_4
这里有一个例子:
<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = join(
', ',
array_map(
function($index) {
return ":an_array_$index";
},
array_keys($ids)
)
);
$db = new PDO(
'mysql:dbname=mydb;host=localhost',
'user',
'passwd'
);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$sqlAnArray.')'
);
foreach ($ids as $index => $id) {
$stmt->bindValue("an_array_$index", $id);
}
如果你想继续使用bindParam,你可以这样做:
foreach ($ids as $index => $id) {
$stmt->bindParam("an_array_$index", $ids[$id]);
}
如果你想用?占位符,你可以这样做:
<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = '?' . str_repeat(', ?', count($ids)-1);
$db = new PDO(
'mysql:dbname=dbname;host=localhost',
'user',
'passwd'
);
$stmt = $db->prepare(
'SELECT *
FROM phone_number_lookup
WHERE country_code IN('.$sqlAnArray.')'
);
$stmt->execute($ids);
如果您不知道$ids是否为空,您应该测试它并相应地处理这种情况(返回一个空数组,或返回一个空对象,或抛出一个异常……)。
你可以这样转换:
$stmt = $db->prepare('SELECT * FROM table WHERE id IN('.$in.')');
在此:
$stmt = $db->prepare('SELECT * FROM table WHERE id IN(:id1, :id2, :id3, :id7, :id8, :id9)');
然后用这个数组执行它:
$stmt->execute(array(
:id1 =>1, :id2 =>2, :id3 =>3, :id7 =>7, :id8 =>8, :id9 => 9
)
);
因此:
$in = array();
$consultaParam = array();
foreach($ids as $k => $v){
$in[] = ':id'.$v;
$consultaParam[':id'.$v] = $v;
}
最后的代码:
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$in = array();
$consultaParam = array();
foreach($ids as $k => $v){
$in[] = ':id'.$v;
$consultaParam[':id'.$v] = $v;
}
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$in.')'
);
$stmt->execute($consultaParam);
为了让答案更接近最初使用占位符绑定参数的问题,我做了一些进一步的处理。
这个答案必须在查询中使用的数组中进行两次循环。但它确实解决了为更有选择性的查询使用其他列占位符的问题。
//builds placeholders to insert in IN()
foreach($array as $key=>$value) {
$in_query = $in_query . ' :val_' . $key . ', ';
}
//gets rid of trailing comma and space
$in_query = substr($in_query, 0, -2);
$stmt = $db->prepare(
"SELECT *
WHERE id IN($in_query)";
//pind params for your placeholders.
foreach ($array as $key=>$value) {
$stmt->bindParam(":val_" . $key, $array[$key])
}
$stmt->execute();