2016-05-05 26 views
0

我必须从具有可变数目属性的$ place对象构建sql语句和params。当我通过构建SQL语句,而params它的工作漫长而糟糕的实践方式(返回所有从数据库中的行,它应该)使用预准备SQL语句:获取call_user_func_array()以使用准备好的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语句,而params的更好的方法,这是行不通的:

<? 

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

悬停在调试器中的$语句显示:提供

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" 

悬停在$查询显示:

"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 = ?" 

为什么它工作时的代码,在这个问题的顶部完成,它不在没有所有陈述的情况下完成代码工作?

+0

最后,您将显示出现故障的查询,您还可以显示正在运行的查询以进行比较吗? –

+0

@JuliePelletier'“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 =?and s.province =?和s.city =?和s.suburb =?“' – BeniaminoBaggins

回答

2

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

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

我已经走下了这条路线,并且因为未知的原因没有工作,但我们用尽了所有尝试这样做的选项。我可以将$ params数组分成多个字符串吗? – BeniaminoBaggins

+0

@Beniamino_Baggins你可以做到这一点,如果数字总是不变的,但从你的代码看起来不是这样。当你尝试这种方法时,你会得到什么错误? – Chris

+0

我意识到我没有添加's.country'等到sql查询中,只有'国家'时指定cloumn这是一个主要问题。我现在已经纠正了这个问题,但它仍然不起作用。 – BeniaminoBaggins

0

传递给call_user_func_array的参数,可以参数2,需要被引用。

这是工作的解决方案:

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

this answer

不知道有关参考周围的东西打乱了我很长一段时间。希望这有助于一些人。