2016-08-09 3 views
4

Я нахожусь в ситуации, когда я хочу создать код, который получает $bindParam переменные в этом формате:

$bindParams = [$type1 => $param1, $type2 => $param2, ... ] 

Я хочу построить некоторый код, который динамически добавляет, что параметры подготовленное заявление.
Это код, который я построил до сих пор:

$mysql = new mysqli("localhost", "root", "", "db1"); 
$stmt = $mysql->prepare($sql); 
foreach($bindParams as $type => $data) { 
    $stmt->bind_param($type, $data); 
} 
$stmt->execute(); 
$result = $stmt->get_result(); 
// and after perhaps twiddling with the result set, but this is not the case ..... 

Для экземпляра

$sql = "INSERT INTO table1 (name, age) VALUES (?,?);" 

и

$bindParams = ["s" => "hello", "i" => 15] 

Это не всегда имеет такую ​​структуру, и она может измениться на например $bindParams = ["s" => "hello", "i" => 15, "d" => 22.5], и поэтому соответственно изменяются $sql.

После первого компилятора головка к $stmt->bind_param($type, $data); светлячку смывает эту ошибку:

Warning: mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in prepared statement in D:\PHP\tr.php on line 23

Я знаю поддержку PDO, что, как указано here at the end of the page., но, возможно, как можно было бы ожидать, Im не поклонник PDO так;)
Моим другим вариантом является использование обходных решений eval(), доступных в php, но это из-за того, что я могу придумать.

Есть ли другой способ сделать это?

+0

@mmm его в разделе «Для вашего примера ...'часть. – TechJS

+0

Покажите свой '$ query' и ваш' $ bindParams'. Если у вас более одного типа, он перезаписывает друг друга, поэтому вы всегда будете иметь 1 любого типа. – aynber

+0

Вы не можете поставить один параметр на два разных вызова для одного и того же вызова. Сначала вы передаете имя, например 'INSERT INTO table1 (имя, возраст) VALUES (" hello ",)' и 'INSERT INTO table1 (имя, возраст) VALUES (, 15)' Вам нужно поставить 2 значения на одинаковые –

ответ

5

К сожалению mysqli не поддерживает это. Вызов функции снова и снова перезаписывает значения, поэтому вы привязываете только один параметр, когда у вас явно больше.

Там есть несколько способов обойти эту

  1. Переключение в PDO. Вы можете сделать одну привязку каждого вызова функции с тем
  2. свяжи PARAMS в один агрегат с помощью call_user_func_array

    $sqltype = ''; 
    $sqldata = []; 
    foreach($bindParams as $type => $data) { 
        $sqltype .= $type; 
        $sqldata[] = &$data; // MUST be a reference 
    } 
    array_unshift($sqldata, $sqltype); // prepend the types 
    call_user_func_array([$stmt, 'bind_param'], $sqldata); 
    
1

Я использую что-то подобное для выполнения динамических вызовов процедур.

Пример вызова:

$mapi = new MySQLIAPI($con); 
    $mapi->BeginProc(); 
    $mapi->AddParameter("user", $usern, "s"); 
    $mapi->AddParameter("email", $email, "s"); 
    $mapi->AddParameter("passwd", $pwd, "s"); 
    $id = $mapi->CallProc("ij_create_user"); 
    $id = $id[0]; 

    if(isset($id['mysql_error']) || isset($id["error"])){ 
     return "error"; 
    } 
    return $id["id"]; 

Пример Класс:

class MySQLIAPI 
{ 
    private $con = null; 
    private $Variables = null; 
    private $values = null; 
    private $types = null; 
    private $vQu = null; 
    private $stmt = null; 
    function __construct($dbc) 
    { 
     $this->con = $dbc; 
      $this->Variables = []; 
     $this->values = []; 
     $this->types = []; 
     $this->vQu = []; 
    } 
    function BeginProc() 
    { 
     $this->stmt = $this->con->stmt_init(); // initialize statement 
    } 

    function AddParameter($key, $val, $type) 
    { 
     $this->Variables[] = "@" . $key; 
     $this->values[] = $val; 
     $this->types[]  = $type; 
     $this->vQu[]  = "?"; 
    } 

    //KeyPair is v = the value, t = the type s or d 
    function CallProc($Proc) { 
     $out_var = null; 

     $call = ""; 
     if(sizeof($this->values) > 0) 
     $call = "CALL ".$Proc."(".implode(",", (array)$this->vQu).")"; 
     else 
     $call = "CALL ".$Proc."()"; 

    if($this->stmt->prepare($call));//call stored procedure with database server session variable 
    { 
     if(sizeof($this->values) > 0) { 
     $params = array_merge(array(implode("", $this->types)), $this->values); 
     call_user_func_array(array($this->stmt, 'bind_param'), $this->refValues($params)); 
     } 

     $this->stmt->execute(); 
     $result = $this->stmt->get_result(); 

     /* Error Checking */ 
     $mySQLiError = mysqli_stmt_error($this->stmt); 
     if ($mySQLiError != "") { 
     $this->resetStmt(); 
     $this->stmt->close(); 
     $this->stmt = null; 
     return array('mysql_error' => $mySQLiError); 
     } 

     while ($row = $result->fetch_array(MYSQLI_ASSOC)) 
     { 
     $out_var[] = $row; 
     } 
     $result->free(); 
     while($this->stmt->more_results()) 
     { 
     $this->stmt->next_result(); 
     } 

     $this->resetStmt(); 
     $this->stmt->close(); 
     $this->stmt = null; 
    } 

    return $out_var; 
    } 
    private function refValues($arr) 
    { 
     if (strnatcmp(phpversion(), '5.3') >= 0) //Reference is required for PHP 5.3+ 
      { 
      $refs = array(); 
      foreach ($arr as $key => $value) 
       $refs[$key] =& $arr[$key]; 
      return $refs; 
     } 
     return $arr; 
    } 
    private function resetStmt() 
    { 
     //Reset Params 
     $this->Variables = array(); 
     $this->values = array(); 
     $this->types  = array(); 
     $this->vQu  = array(); 
    } 
} 
+0

Что такое' mapi': | Пожалуйста, подтвердите свой ответ – TechJS

+0

извините, что @TechJS mapi - это просто переменная экземпляра класса MySQLIAPI. – JQluv

5

У меня была такая же проблема, и нашел ответ много проще:

$array_of_values = array("Brasil", "Argentina"); 
$types = "ss"; 
$mysqli_stmt->bind_param($types, ...$array_of_values); 

Это называется «распаковка аргументов» и доступно с PHP 5.6

+0

Его долгое время с тех пор, как я боролся с этой проблемой. Но спасибо за ваши мысли. Я применим ваше решение и посмотрю, будет ли оно работать, как только я снова столкнулся с проблемой. – TechJS

+0

ok, у меня была эта проблема недавно, и я нашел эту страницу. –

Смежные вопросы