php - 让 call_user_func_array() 使用准备好的 sql 语句

标签 php mysql

我必须从具有可变数量属性的 $place 对象构建一条 sql 语句和参数。当我通过构建 sql 语句和参数来使用准备好的 sql 语句时,它的工作方式是漫长而糟糕的实践方式(从数据库返回它应该返回的所有行):

<?

function buildSQLWhereClause($query, $conn, $place) {
    if ($place['suburb']){
        if($place['city'] && $place['province'] && $place['country']) {
            $query .= "s.country = ? and 
                    s.province = ? and
                    s.city = ? and 
                    s.suburb = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("ssss", $place['country'], $place['province'], $place['city'], $place['suburb']);
        } else if ($place['province'] && $place['country']) {
            $query .= "s.country = ? and 
                    s.province = ? and
                    s.suburb = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("sss", $place['country'], $place['province'], $place['suburb']);
        } else if ($place['city'] && $place['province']) {
            $query .= "s.province = ? and
                    s.city = ? and 
                    s.suburb = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("sss", $place['province'], $place['city'], $place['suburb']);
        } else if ($place['city'] && $place['country']) {
            $query .= "s.country = ? and
                    s.city = ? and 
                    s.suburb = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("sss", $place['country'], $place['city'], $place['suburb']);
        } else if ($place['city']) {
            $query .= "s.city = ? and 
                    s.suburb = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("ss", $place['city'], $place['suburb']);
        } else if ($place['province']) {
            $query .= "s.province = ? and 
                    s.suburb = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("ss", $place['province'], $place['suburb']);
        } else if ($place['country']) {
            $query .= "s.country = ? and 
                    s.suburb = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("ss", $place['country'], $place['suburb']);
        } else {
            $query .= "s.suburb = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("s", $place['suburb']);
        }
//////////////////////////// NO SUBURB ///////////////////////////////////////////////////        
    } else if ($place['city']) {
        if ($place['province'] && $place['country']) {
            $query .= "s.country = ? and 
                    s.province = ? and
                    s.city = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("sss", $place['country'], $place['province'], $place['city']);
        } else if ($place['province']) {
            $query .= "s.province = ? and
                    s.city = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("ss", $place['province'], $place['city']); 
        } else if ($place['country']) {
            $query .= "s.country = ? and
                    s.city = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("ss", $place['country'], $place['city']); 
        } else {
            $query .= "s.city = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("s", $place['city']); 
        }
//////////////////////// NO SUBURB OR CITY ////////////////////////////////////////////////////////
    } else if ($place['province']) {
        if ($place['country']) {
            $query .= "s.country = ? and
                    s.province = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("ss", $place['country'], $place['province']); 
        } else {
            $query .= "s.province = ?";

            // prepare and bind
            $stmt = $conn->prepare($query);

            $stmt->bind_param("s", $place['province']); 
        }
//////////////////////////////// NO SUBURB, CITY, OR PROVINCE ///////////////////////////////        
    } else if ($place['country']) {
        $query .= "s.country = ?";

        // prepare and bind
        $stmt = $conn->prepare($query);

        $stmt->bind_param("s", $place['country']); 
    }

    return $stmt;
}

function queryDbForProducts($conn, $place)
{   

    $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 ";

    $stmt = buildSQLWhereClause($query, $conn, $place);

    $stmt->execute();
    $meta = $stmt->result_metadata();

    while ($field = $meta->fetch_field()) {
        $parameters[] =& $row[$field->name];
    }

当我通过以更好的方式构建 sql 语句和参数来使用 sql 准备好的语句时,它不起作用:

<?

function buildSQLWhereClause($place) {
    $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 ";
    $queryParams = [];
    $queryParamTypes = "";
    $i = 0;
    $len = count($place);
    foreach ($place as $key => $value) {
        if ($i == $len - 1) {
            $query .= "$key = ?";
            $queryParams[] = $value;
            $queryParamTypes .= "s";
        } else {
            $query .= "$key = ? AND ";
            $queryParams[] = $value;
            $queryParamTypes .= "s";
        }
        $i++;
    }

    return array(
            "query" => $query,
            "queryParams" => $queryParams,
            "queryParamTypes" => $queryParamTypes
        );
}

function queryDbForProducts($conn, $place)
{   
    $queryObject = buildSQLWhereClause($place);
    $query = $queryObject['query'];
    $queryParams = $queryObject['queryParams'];
    $queryParamTypes = $queryObject['queryParamTypes'];


    // prepare and bind
    $stmt = $conn->prepare($query);
    $stmt->bind_param($queryParamTypes, $queryParams); 
    $stmt->execute();
    $meta = $stmt->result_metadata();

将鼠标悬停在调试器中的 $stmt 上会显示:

affected_rows:-1
insert_id:0
num_rows:0
param_count:4
field_count:13
errno:2031
error:"No data supplied for parameters in prepared statement"
error_list:array(1)
sqlstate:"HY000"
id:1

没有提供数据?将鼠标悬停在调试器中的 $queryParams 参数上会显示:

0:"Grey Lynn"
1:"Auckland"
2:"Auckland"
3:"New Zealand"

所以我确实向 $stmt->bind_param() 函数提供了查询参数。我提供的格式是否错误?

将鼠标悬停在 $QueryParamTypes 上会显示:

"ssss"

将鼠标悬停在 $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 suburb = ? AND city = ? AND province = ? AND country = ?"

为什么在问题顶部的代码完成时它可以工作,而在没有所有 is 语句的代码完成时它不起作用?

最佳答案

bind_param不接受数组作为参数,它接受可变参数。您将需要使用call_user_func_array如果您想使用动态数量的参数来调用它。

$params = array_unshift($queryParams, $queryParamTypes);
call_user_func_array(array($stmt, "bind_param"), $params);

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

相关文章:

javascript - 动态加载图像缓慢,jquery,php

php - 更改 WordPress/WooCommerce 商店中的按钮位置

MySql Toad 如果现在行返回值

php - 如何计算 MySQL 存储过程中的年龄?

mysql - 如何将这两个 Select 查询与 OR 案例结合起来

php - 如何编写带有更新的准备好的语句?

php - 按值增加字段

php - 在 Doctrine 中,如何忽略更新模式命令中的特定列?

php - MySQL 查询选择两个用户之间的冲突计数

mysql - 子表变量允许 NULL 但 ON DELETE SET NULL 仍然不起作用?