Используйте один bind_param () с переменным числом входных vars

Я пытаюсь использовать привязку переменной следующим образом:

$stmt = $mysqli->prepare("UPDATE mytable SET myvar1=?, myvar2=... WHERE id = ?")) { $stmt->bind_param("ss...", $_POST['myvar1'], $_POST['myvar2']...); 

но некоторые из $ _POST ['…'] могут быть пустыми, поэтому я не хочу обновлять их в БД.

Нецелесообразно учитывать всю комбинацию пустых $ _POST ['…'], и хотя я могу построить строку «UPDATE mytable SET …» для моих нужд, bind_param () – это другой зверь.

Я мог бы попытаться построить свой вызов как строку и использовать eval () на нем, но он не чувствует себя хорошо 🙁

Вы можете использовать функцию call_user_func_array для вызова метода bind_param с переменным числом или аргументами:

 $paramNames = array('myvar1', 'myvar2', /* ... */); $params = array(); foreach ($paramNames as $name) { if (isset($_POST[$name]) && $_POST[$name] != '') { $params[$name] = $_POST[$name]; } } if (count($params)) { $query = 'UPDATE mytable SET '; foreach ($params as $name => $val) { $query .= $name.'=?,'; } $query = substr($query, 0, -1); $query .= 'WHERE id = ?'; $stmt = $mysqli->prepare($query); $params = array_merge(array(str_repeat('s', count($params))), array_values($params)); call_user_func_array(array(&$stmt, 'bind_param'), $params); } 

Это то, что я использую для выполнения подготовленных операторов mysqli с переменным количеством параметров. Это часть класса, который я написал. Это, возможно, слишком велико для того, что вам нужно, но оно должно показать вам правильное направление.

 public function __construct($con, $query){ $this->con = $con; $this->query = $query; parent::__construct($con, $query); //We check for errors: if($this->con->error) throw new Exception($this->con->error); } protected static $allowed = array('d', 'i', 's', 'b'); //allowed types protected static function mysqliContentType($value) { if(is_string($value)) $type = 's'; elseif(is_float($value)) $type = 'd'; elseif(is_int($value)) $type = 'i'; else throw new Exception("type of '$value' is not string, int or float"); return $type; } //This function checks if a given string is an allowed mysqli content type for prepared statement (s, d, b, or i) protected static function mysqliAllowedContentType($s){ return in_array($s, self::$allowed); } public function feed($params){ //These should all be empty in case this gets used multiple times $this->paramArgs = array(); $this->typestring = ''; $this->params = $params; $this->paramArgs[0] = ''; $i = 0; foreach($this->params as $value){ //We check the type: if(is_array($value)){ $temp = array_keys($value); $type = $temp[0]; $this->params[$i] = $value[$type]; if(!self::mysqliAllowedContentType($type)){ $type = self::mysqliContentType($value[$type]); } } else{ $type = self::mysqliContentType($value); } $this->typestring .= $type; //We build the array of values we pass to the bind_params function //We add a refrence to the value of the array to the array we will pass to the call_user_func_array function. Thus say we have the following //$this->params array: //$this->params[0] = 'foo'; //$this->params[1] = 4; //$this->paramArgs will become: //$this->paramArgs[0] = 'si'; //Typestring //$this->paramArgs[1] = &$this->params[0]; //$this->paramArgs[2] = &$this->params[1]. //Thus using call_user_func_array will call $this->bind_param() (which is inherented from the mysqli_stmt class) like this: //$this->bind_param( 'si', &$this->params[0], &$this->params[1] ); $this->paramArgs[] = &$this->params[$i]; $i++; } unset($i); $this->paramArgs[0] = $this->typestring; return call_user_func_array(array(&$this, 'bind_param'), $this->paramArgs); } с public function __construct($con, $query){ $this->con = $con; $this->query = $query; parent::__construct($con, $query); //We check for errors: if($this->con->error) throw new Exception($this->con->error); } protected static $allowed = array('d', 'i', 's', 'b'); //allowed types protected static function mysqliContentType($value) { if(is_string($value)) $type = 's'; elseif(is_float($value)) $type = 'd'; elseif(is_int($value)) $type = 'i'; else throw new Exception("type of '$value' is not string, int or float"); return $type; } //This function checks if a given string is an allowed mysqli content type for prepared statement (s, d, b, or i) protected static function mysqliAllowedContentType($s){ return in_array($s, self::$allowed); } public function feed($params){ //These should all be empty in case this gets used multiple times $this->paramArgs = array(); $this->typestring = ''; $this->params = $params; $this->paramArgs[0] = ''; $i = 0; foreach($this->params as $value){ //We check the type: if(is_array($value)){ $temp = array_keys($value); $type = $temp[0]; $this->params[$i] = $value[$type]; if(!self::mysqliAllowedContentType($type)){ $type = self::mysqliContentType($value[$type]); } } else{ $type = self::mysqliContentType($value); } $this->typestring .= $type; //We build the array of values we pass to the bind_params function //We add a refrence to the value of the array to the array we will pass to the call_user_func_array function. Thus say we have the following //$this->params array: //$this->params[0] = 'foo'; //$this->params[1] = 4; //$this->paramArgs will become: //$this->paramArgs[0] = 'si'; //Typestring //$this->paramArgs[1] = &$this->params[0]; //$this->paramArgs[2] = &$this->params[1]. //Thus using call_user_func_array will call $this->bind_param() (which is inherented from the mysqli_stmt class) like this: //$this->bind_param( 'si', &$this->params[0], &$this->params[1] ); $this->paramArgs[] = &$this->params[$i]; $i++; } unset($i); $this->paramArgs[0] = $this->typestring; return call_user_func_array(array(&$this, 'bind_param'), $this->paramArgs); } 

Вы используете его следующим образом:

  $prep = new theClassAboveHere( $mysqli, $query ); $prep->feed( array('string', 1, array('b', 'BLOB DATA') ); 

Класс должен расширить класс mysqli_stmt.

Надеюсь, это поможет вам в правильном направлении.
Если вы не можете опубликовать весь класс, он включает в себя привязку переменных результатов.

Немного более понятно построить ваше заявление с помощью массива:

 $params = array(); $fragments = array(); foreach($_POST as $col => $val) { $fragments[] = "{$col} = ?"; $params[] = $val; } $sql = sprintf("UPDATE sometable SET %s", implode(", ", $fragments)); $stmt = $mysqli->prepare($sql); $stmt->bind_param($params); 

array_insert не существует, я предполагаю, что он ссылается на некоторую домашнюю функцию, но я точно не знаю, что она делает … вставляет типы параметров в массив где-то в начале, я бы угадал, поскольку значение 0 передано но эй, может, и в конце концов тоже);

Создайте его как строку, но поместите свои значения в массив и передайте это в bindd_param. (и замените?) на значения в вашей строке SQL.

$ stmt = $ mysqli-> prepare ("UPDATE mytable SET myvar1 = ?, myvar2 = … WHERE id =?")) {$ stmt-> bind_param ("ss …", $ _POST ['myvar1'] , $ _POST ['myvar2'] …);

Например:

 $args = array(); $sql = "UPDATE sometable SET "; $sep = ""; $paramtypes = ""; foreach($_POST as $key => $val) { $sql .= $sep.$key." = '?'"; $paramtypes .= "s"; // you'll need to map these based on name array_push($args, $val); $sep = ","; } $sql .= " WHERE id = ?"; array_push($args, $id); array_insert($args, $paramtypes, 0); $stmt = $mysqli->prepare($sql); call_user_func_array(array(&$stmt, 'bindparams'), $array_of_params); $stmt->bind_param($args);