У меня есть функция в PHP, которая должна связывать в MySQL IN так много переменных, которые находятся в массиве. Моя проблема в том, что переменная и ключ меняются, но функция связывает только последнее значение n раз.
У меня нет идеи, где проблема …
Вот мой метод класса:
public function getOtListByOtNumbers($conditions){ $data_array = $conditions[SEARCH_OT]; # To find last key (remove coma) $quantity = count($data_array); $marks = ''; # Bind name string && rewriting value as integer foreach ($data_array as $key => $value){ $i = $key+1; if ($i == $quantity){ $marks .= ':key'.$i; } else { $marks .= ':key'.$i.', '; } } # Query $sql=" SELECT c_int_id, c_ot, c_tickets_amount, c_basket_value, c_person, c_company, c_city, c_package_number, c_delivery_method, c_ot_date, c_email, c_phone, c_comment, c_send FROM ws_orders WHERE c_ot IN (".$marks.") ORDER BY c_int_id DESC LIMIT :first, :last "; $stmt = $this->PDO->prepare($sql); # Bind n values // Here is a problem var_dump($data_array); // var dump 1 foreach ($data_array as $key => $param){ $key_number = $key +1; $key_name = 'key'.$key_number; $stmt->bindParam($key_name, $param, PDO::PARAM_INT); var_dump($key_name); // var dump 2 var_dump($param); // var dump 3 } # Bind limit values $stmt->bindParam('first', $conditions[OT_SEARCH_FIRST_ROW], PDO::PARAM_INT); $stmt->bindParam('last', $conditions[OT_SEARCH_ROW_LIMIT], PDO::PARAM_INT); # If executed return result if ($stmt->execute() != FALSE) { $stmt_result = $stmt->fetchAll(); $stmt->closeCursor(); var_dump($stmt_result); // var dump 4 # If not executed print debug and return FALSE } else { var_dump($stmt->errorInfo()); $this->debugQuery($stmt); $stmt_result = FALSE; } return $stmt_result; }
Вот var dupms:
var dump 1
array (size=2) 0 => string '2761531' 1 => string '2760650'
var dump 2 & 3
string 'key1' (length=4) string '2761531' string 'key2' (length=4) string '2760650'
SQL-запрос из этого выполнения
SELECT c_int_id, c_ot, c_tickets_amount, c_basket_value, c_person, c_company, c_city, c_package_number, c_delivery_method, c_ot_date, c_email, c_phone, c_comment, c_send FROM ws_orders WHERE c_ot IN ('2760650', '2760650') ORDER BY c_int_id DESC LIMIT 0, 30
Так что я делаю неправильно?
РЕДАКТИРОВАТЬ
Так что я сделал это;) Проблема была в foreach
Вместо:
foreach ($data_array as $key => $param){ $key_number = $key +1; $key_name = 'key'.$key_number; $stmt->bindParam($key_name, $param, PDO::PARAM_INT); var_dump($key_name); // var dump 2 var_dump($param); // var dump 3 }
Я даю:
for ($key_number = 0; $key_number < $quantity + 1; $key_number++) { $key_name = 'key'.$key_number; $stmt->bindParam($key_name, $data_array[$key_number], PDO::PARAM_INT); }
И это работает, но я до сих пор не знаю, в чем проблема с предыдущим foreach …
Существует различие между PDO::bindParam()
и PDO::bindValue()
. PDO::bindParam
связывает ссылку , а не значение. Когда процесс foreach завершается, $param
будет ссылаться на последнее значение массива. Во время execute
вызова все привязанные ссылки будут оцениваться с одинаковым значением.
Официальная документация PDO::bindParam
гласит:
В отличие от PDOStatement :: bindValue () переменная привязана как ссылка и будет оцениваться только в момент вызова PDOStatement :: execute ().
Если вы хотите, чтобы значения привязки в foreach
использовали PDO::bindValue
.
Если вы передадите переменную в качестве ссылки, она будет работать нормально для значения, но не будет работать для ключа.
Пример:
foreach ($data_array as $key => &$param) { $key_number = $key + 1; //this won't work $key_name = 'key' . $key_number; $stmt->bindParam($key_name, $param, PDO::PARAM_INT); var_dump($key_name); // var dump 2 var_dump($param); // var dump 3 }
Проблема в том, что BindParam передает второе значение по ссылке. PHP повторно использует (или появляется в этом случае) адрес $ param, а не фактическое значение. Ваш foreach мог бы использовать:
$stmt->bindParam($key, $data_array[$key]);
Это приводит к привязке адресного адреса массива к этому месту ключа, поэтому, когда ваш sql выполняется, он получает правильное значение.
Вы, наверное, хотели:
$stmt->bindValue($key, $param);
который должен оцениваться в цикле foreach вместо инструкции execute и является переданным значением вместо адреса.