php - 使用 call_user_func_array() 动态构建准备好的语句

标签 php mysql mysqli

<分区>

我需要根据用户输入动态构建 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 的开头所以我这样做了并在 $stmt 对象中得到了这个错误:

errno:2031
error:"No data supplied for parameters in prepared statement"
error_list:array(1)
propertyNode.hasAttribute is not a function

最佳答案

我不明白你尝试了哪些方法,但我会尽力回答:

根据 bind_param manual :

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);

关于php - 使用 call_user_func_array() 动态构建准备好的语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36964362/

相关文章:

php: 从 html 中解析字符串

php - 使用 session 获取多个数组值

php - 显示一次选择自动完成jquery的人的信息

mysql - 如何使用选择查询查找表名

php - 通过仅具有登录凭据的 LDAP 和 PHP 获取用户可读的名称

mysql - PostgreSQL vs MySQL 简单查询性能

数据库; GROUP BY 但仅当列不为空时

php - mySql 查询未找到该行

PHP MySQLi 在不执行 while 循环的情况下回显数组中的数据

PHP 不向表中插入新数据