Связывание параметров MySQLI с помощью call_user_func_array - PullRequest
12 голосов
/ 16 декабря 2009

Пожалуйста, смотрите ниже мой код. Я пытаюсь привязать множество параметров к моему подготовленному заявлению. Я искал в Интернете и вижу, что должен использовать call_user_func_array, но не могу заставить его работать. Я получаю ошибку: «Предполагается, что первым аргументом будет действительный обратный вызов, был задан массив» Я могу ошибаться, но я предполагаю, что первый аргумент может быть массивом, и, возможно, это сообщение об ошибке вводит в заблуждение. Я думаю, проблема в том, что мой массив каким-то образом виноват. Кто-нибудь может увидеть, что я делаю не так? Спасибо.

$type = array("s", "s");
$param = array("string1","anotherstring");

$stmt = $SQLConnection->prepare("INSERT INTO mytable (comp, addl) VALUES (?,?)");

$params = array_merge($type, $param);

call_user_func_array(array(&$stmt, 'bind_param'), $params);
$SQLConnection->execute();

Ответы [ 7 ]

18 голосов
/ 12 июля 2014

Должно быть так:

//connect
$mysqli = new mysqli($host, $user, $password, $db_name);

//prepare
$stmt = $mysqli->prepare("SELECT * FROM the_table WHERE field1= ? AND Field2= ?");

//Binding parameters. Types: s = string, i = integer, d = double,  b = blob
$params= array("ss","string_1","string_2");

//now we need to add references
$tmp = array();
foreach($params as $key => $value) $tmp[$key] = &$params[$key];
// now us the new array
call_user_func_array(array($stmt, 'bind_param'), $tmp);

$stmt->execute();

/* Fetch result to array */
$res = $stmt->get_result();
while($row = $res->fetch_array(MYSQLI_ASSOC)) {
  $a_data[]=$row;
}
print_r($a_data);

$stmt->close();
9 голосов
/ 16 декабря 2009

Я не знаю, почему нужно использовать call_user_func_array, но это уже другая история.

Единственное, что может быть не так в моих глазах, это то, что вы используете ссылку на объект. Предполагая, что вы используете PHP 5. *, в этом нет необходимости:

call_user_func_array(array($stmt, 'bind_param'), $params);
4 голосов
/ 04 июня 2018

Поскольку PHP 5.6 , вам больше не придется возиться с call_user_func_array().

Вместо:

$stmt->bind_param($param_types, $my_params_array);

вы можете просто использовать оператор сплата , например:

$stmt->bind_param($param_types, ...$my_params_array); // exact code

1 голос
/ 03 января 2018

Большинство из вышеперечисленного не являются решениями без интеграции типов со значениями перед добавлением их в call_user_func_array (). Это решение работало для меня:

/* create a database connection */
$db = new mysqli($host, $user, $password, $db_name);

/* setup the sql, values, and types */
$sql="SELECT * FROM languages 
         WHERE language_code = ?
           AND charset = ?
         ORDER BY native_name";
$values = array($langCode, $charset);
$types = "ss";   

/* pass those variables to the execute() function defined below */
if ($rows = execute($sql, $values, $types))
{
   return $rows[0];
}

function execute($sql, $values='', $types='')
{
   /* prepare the sql before binding values and types */
   $stmt = $db->prepare($sql);

   /*combine the values and types into $inputArray */
   $inputArray[] = &$types;
   $j = count($values);
   for($i=0;$i<$j;$i++){
     $inputArray[] = &$values[$i];
   }
   /* add the combined values and types to call_user_func_array() for binding */
   call_user_func_array(array($stmt, 'bind_param'), $inputArray);
   $result = $stmt->execute();
   return $result;
}

Вот ссылка на полное описание, на котором основан этот пример: http://big.info/2015/08/php-use-call_user_func_array-for-variable-number-of-parameters-arrays-in-prepared-statements.html

1 голос
/ 16 декабря 2017

Не смог ответить на мой вопрос, потому что он был помечен как дублирующий: здесь . Но я думаю, что мое окончательное решение, использующее ответы на этот вопрос, работает в моем случае, может быть полезным для кого-то.

Моей целью было взять опубликованный набор идентификаторов и использовать их в NOT IN выражении MYSQL. Предполагается, что массив из 5 идентификаторов размещен.

  1. Подсчитайте количество отправленных идентификаторов, чтобы построить заполнители ? для оператора NOT IN. Использование $params_count = substr(str_repeat(',?', count($array_of_ids)), 1); дает результат: (?,?,?,?,?) для использования в операторе SQL.

  2. Создайте функцию, которая принимает ID и введите i или s и т. Д. Для меня все они были i, поэтому моя функция проще. возвращаемый массив, который выглядит следующим образом $params= array("iiiii",1,2,3,4,5), где первое значение - это набор i, а последующие значения - это идентификаторы в зависимости от общего идентификатора, переданного в функцию.

    function build_bind_params($values, $bind_type) {
        $s = substr(str_repeat($bind_type, count($values)), 0);
        $bind_array = array();
        $bind_array[] = $s;
        foreach($values as $value) {
            $bind_array[] = $value;
        }
        return $bind_array; 
    }
    

$params = build_bind_params($array_of_ids, "i");

  1. Затем используйте foreach ($params as $key => $value) $tmp[$key] = &$params[$key];, чтобы получить вновь созданный $params, отформатированный должным образом для привязки.

  2. Затем используйте call_user_func_array(array($stmt , 'bind_param') , $tmp);, чтобы правильно связать массив.

  3. Затем выполните $stmt

0 голосов
/ 05 ноября 2016

Если вы получили ошибку, попробуйте следующее:

call_user_func_array(array($stmt, 'bind_param'), refValues($params));

function refValues($arr){
    if (strnatcmp(phpversion(),'5.3') >= 0) {
        $refs = array();
        foreach($arr as $key => $value)
            $refs[$key] = &$arr[$key];
        return $refs;
    }
    return $arr;
}
0 голосов
/ 22 февраля 2016

Зачем вам вызывать call_user_func_array (массив (оператор $, 'bind_param'), $ bind_arguments)? Потому что $ bind_arguments - это массив. Вы получаете одну функцию, которая связывает оператор с его запрашиваемыми параметрами, независимо от того, сколько параметров у вас было бы в противном случае.

Пример хорошего кода ...

    <?php
            # link
        $dblink = new mysqli('HOSTNAME','USERNAME','PASSWORD','DATABASENAME');

            # example data
        $statement = $dblink->prepare("SELECT * from Person WHERE FirstName = ? AND MiddleName = ? AND LastName = ? and Age = ?");
        $recordvalues = ['John', 'H.', 'Smith', 25];
        $sqlbindstring = "sssi";    # String, String, String, Integer example

            # make the references
        $bind_arguments = [];
        $bind_arguments[] = $sqlbindstring;
        foreach ($recordvalues as $recordkey => $recordvalue)
        {
            $bind_arguments[] = & $recordvalues[$recordkey];    # bind to array ref, not to the temporary $recordvalue
        }

            # query the db
        call_user_func_array(array($statement, 'bind_param'), $bind_arguments);     # bind arguments
        $statement->execute();  # run statement
        $result = $statement->get_result(); # get results

            # get the results
        if($result) {
            while ($row = $result->fetch_assoc()) {
                print("\n\nMy row is...");
                print_r($row);
            }
        }
    ?>

Пример плохого кода ...

    <?php

            # Same setup as above..

        $statement->prepare("SELECT * from Person WHERE FirstName = ? AND MiddleName = ? AND LastName = ? and Age = ?");
        $statement->bind('John', 'H.", 'Smith', 25);

    ?>

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

Во втором примере: вы должны написать один оператор bind () для каждой возможной группы вставок для каждой возможной записи в вашей базе данных. Это плохо масштабируется.

...