我需要根据用户输入动态构建SQL语句和参数。 sql语句的长度和参数的数量根据用户输入而变化。我正在尝试使用this tutorial并将其应用于我的代码。这是代码:
$query = "SELECT p.*, s.*
FROM product p
INNER JOIN product_shop ps
ON ps.p_id = p.p_id
INNER JOIN shop s
ON s.s_id = ps.s_id
WHERE s.country = ?";
$a_params[] = $place['country'];
$a_param_type[] = "s";
// prepare and bind
$param_type = '';
foreach ($place as $key => $value) {
if ($key === "country") {
continue;
}
$query .= " and s.$key = ?";
$a_params[] = $value;
$a_param_type[] = "s";
}
/* Prepare statement */
$stmt = $conn->prepare($query);
if($stmt === false) {
trigger_error('Wrong SQL: ' . $sql . ' Error: ' . $conn->errno . ' ' . $conn->error, E_USER_ERROR);
}
$a_params[] = $a_param_type;
/* use call_user_func_array, as $stmt->bind_param('s', $param); does not accept params array */
call_user_func_array(array($stmt, 'bind_param'), $a_params);
/* Execute statement */
$stmt->execute();
$meta = $stmt->result_metadata();
我知道$place['country']
将永远填充。 sql语句是正确的。它是:
"SELECT p.*, s.* \n FROM product p \n INNER JOIN product_shop ps \n ON ps.p_id = p.p_id \n INNER JOIN shop s \n ON s.s_id = ps.s_id \n WHERE s.country = ? and s.suburb = ? and s.city = ? and s.province = ?"
不介意“\ n”字符,它们对sql语句没有影响。
在:
call_user_func_array(array($stmt, 'bind_param'), $a_params);
$a_params
的值是:
0:"New Zealand"
1:"Grey Lynn"
2:"Auckland"
3:"Auckland"
4:array(4)
0:"s"
1:"s"
2:"s"
3:"s"
在:
$meta = $stmt->result_metadata();
$ meta的值变为:
current_field:0
field_count:13
lengths:null
num_rows:0
type:1
表示没有从数据库中选择任何行。我已手动在数据库上执行此sql并返回行。我的代码出了什么问题,使得它不返回数据库中的行?
编辑:我看到this answer说要将“ssss”放在$params
的开头,所以我这样做并在{{1}中出现此错误object:
$stmt
答案 0 :(得分:2)
我不明白你尝试过的方法,但我会尽力回答:
bind_param
的第一个参数是字符串,例如'ssss'
。
第二个和其他参数 - 是要插入查询的值。
因此,您的$a_params
数组应不
0:"New Zealand"
1:"Grey Lynn"
2:"Auckland"
3:"Auckland"
4:array(4)
0:"s"
1:"s"
2:"s"
3:"s"
可是:
0:"ssss"
1:"New Zealand"
2:"Grey Lynn"
3:"Auckland"
4:"Auckland"
请参阅?所有值都是字符串。和占位符'类型是第一个。
还要考虑$a_params
中参数的顺序必须与bind_param
中参数的顺序相同。这意味着,即$a_params
喜欢
0:"New Zealand"
1:"Grey Lynn"
2:"Auckland"
3:"Auckland"
4:"ssss"
错了。因为$a_params
的第一个元素将是bind_param
的第一个参数,在这种情况下,它不是"ssss"
字符串。
所以,这意味着在你用$a_params
填充值,占位符'之后字符串应添加到$a_params
的开头,例如array_unshift
:
// make $a_param_type a string
$str_param_type = implode('', $a_param_type);
// add this string as a first element of array
array_unshift($a_params, $str_param_type);
// try to call
call_user_func_array(array($stmt, 'bind_param'), $a_params);
如果这不起作用,您可以引用answer you provided的一部分,其中$a_params
的值通过引用另一个数组$tmp
传递,在您的情况下你可以尝试类似的东西:
// make $a_param_type a string
$str_param_type = implode('', $a_param_type);
// add this string as a first element of array
array_unshift($a_params, $str_param_type);
$tmp = array();
foreach ($a_params as $key => $value) {
// each value of tmp is a reference to `$a_params` values
$tmp[$key] = &$a_params[$key];
}
// try to call, note - with $tmp, not with $a_params
call_user_func_array(array($stmt, 'bind_param'), $tmp);
答案 1 :(得分:2)
记住:需要引用call_user_func_array
的第二个参数,而不仅仅是普通数组。这是关键。接受的答案是好的,但只缺少一件事,使参数参考:
function makeValuesReferenced($arr){
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
$stmt = $conn->prepare($query);
//$stmt->bind_param($queryParamTypes, $queryParams);
call_user_func_array(array($stmt, 'bind_param'), makeValuesReferenced($queryParams));
$stmt->execute();