Вызов неопределенного метода mysqli_stmt :: get_result


113

Вот мой код:

include 'conn.php';
$conn = new Connection();
$query = 'SELECT EmailVerified, Blocked FROM users WHERE Email = ? AND SLA = ? AND `Password` = ?';
$stmt = $conn->mysqli->prepare($query);
$stmt->bind_param('sss', $_POST['EmailID'], $_POST['SLA'], $_POST['Password']);
$stmt->execute();
$result = $stmt->get_result();

Я получаю сообщение об ошибке в последней строке как: Вызов неопределенного метода mysqli_stmt :: get_result ()

Вот код для conn.php:

define('SERVER', 'localhost');
define('USER', 'root');
define('PASS', 'xxxx');
define('DB', 'xxxx');
class Connection{
    /**
     * @var Resource 
     */
    var $mysqli = null;

    function __construct(){
        try{
            if(!$this->mysqli){
                $this->mysqli = new MySQLi(SERVER, USER, PASS, DB);
                if(!$this->mysqli)
                    throw new Exception('Could not create connection using MySQLi', 'NO_CONNECTION');
            }
        }
        catch(Exception $ex){
            echo "ERROR: ".$e->getMessage();
        }
    }
}

Если я напишу эту строку:

if(!stmt) echo 'Statement prepared'; else echo 'Statement NOT prepared';

Он печатает «Заявление НЕ подготовлено» . Если я запустил запрос прямо в IDE, заменив? отмечает со значениями, работает нормально. Обратите внимание, что объект $ conn отлично работает с другими запросами в проекте.

Любая помощь, пожалуйста .......


Я думаю, ты забыл $stmt = $conn->mysqli->stmt_init();?
favoretti

Пожалуйста, проверьте, $_POST['EmailID'], $_POST['SLA'], $_POST['Password']правильно ли отправлены эти переменные, используя HTML-форму с методом POST
ajreal

@ajreal: переменные размещаются правильно. Я тестировал их с помощью print_r ($ _ POST).
Кумар Куш

@favoretti: я пробовал использовать $ stmt = $ conn-> mysqli-> stmt_init (); . По-прежнему не повезло.
Кумар Куш

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

Ответы:


146

Прочтите примечания пользователя для этого метода:

http://php.net/manual/en/mysqli-stmt.get-result.php

Для этого требуется драйвер mysqlnd ... если он не установлен в вашем веб-пространстве, вам придется работать с BIND_RESULT & FETCH!

https://secure.php.net/manual/en/mysqli-stmt.bind-result.php

https://secure.php.net/manual/en/mysqli-stmt.fetch.php


4
Большое спасибо. Это сработало. Я раскомментировал extension = php_mysqli_mysqlnd.dll в php.ini ; и перезапустили службы Apache2.2 и MySQL. Следует ли раскомментировать строку extension = php_mysqli_libmysql.dll ? Согласно другой странице, mysqlnd быстрее, чем libmysql. Кроме того, могу ли я ожидать, что mysqlnd будет установлен на большинстве популярных поставщиков услуг хостинга?
Кумар Куш

1
stmt_init () требуется только для процедурно подготовленного оператора. так что вам это не нужно! Смотри: ссылка Насчет libmysql : не знаю. И я бы не стал рассчитывать на то, что хостинг-провайдеры установят mysqlnd.dll ... лучше попробуйте какой-нибудь обходной путь!
bekay 01

2
Примечание: mysqli_stmt::get_result()доступно только в PHP v5.3.0 или выше.
Raptor

4
@bekay Вы только что сохранили мне новый ноутбук и новое окно. Если бы было доступно +10, я бы дал вам это
Джеймс Кушинг

1
@ kush.impetus, где скачать php_mysqli_mysqlnd.dll? Я бы только php_mysqli.dllв extпапке.
Pacerier

51

Поэтому, если драйвер MySQL Native Driver (mysqlnd) недоступен и, следовательно, с использованием bind_result и fetch вместо get_result , код становится следующим:

include 'conn.php';
$conn = new Connection();
$query = 'SELECT EmailVerified, Blocked FROM users WHERE Email = ? AND SLA = ? AND `Password` = ?';
$stmt = $conn->mysqli->prepare($query);
$stmt->bind_param('sss', $_POST['EmailID'], $_POST['SLA'], $_POST['Password']);
$stmt->execute();
$stmt->bind_result($EmailVerified, $Blocked);
while ($stmt->fetch())
{
   /* Use $EmailVerified and $Blocked */
}
$stmt->close();
$conn->mysqli->close();

$ stmt-> bind_result экономит мое время. Это отличное решение, когда get_result недоступен.
Zafer

2
вопрос: откуда взялась переменная $ EmailVerfied?
Rotimi

@ Akintunde007: $EmailVerfiedсоздается при вызове bind_result().
AbraCadaver

Получение ошибки «Неперехваченная ошибка: вызов неопределенного метода mysqli_stmt :: bind_results ()» при использовании кода
Devil's Dream

Если у меня есть запрос sql, например «Выбрать * из table_name», то как объявить внутри bind_result (). * оператор
Inderjeet 07

46

В вашей системе отсутствует драйвер mysqlnd!

Если вы можете установить новые пакеты на свой сервер (на базе Debian / Ubuntu), установите драйвер:

sudo apt-get install php5-mysqlnd

а затем перезапустите свой веб-сервер:

sudo /etc/init.d/apache2 restart

39

для тех, кто ищет альтернативу, $result = $stmt->get_result()я сделал эту функцию, которая позволяет имитировать, $result->fetch_assoc()но напрямую использовать объект stmt:

function fetchAssocStatement($stmt)
{
    if($stmt->num_rows>0)
    {
        $result = array();
        $md = $stmt->result_metadata();
        $params = array();
        while($field = $md->fetch_field()) {
            $params[] = &$result[$field->name];
        }
        call_user_func_array(array($stmt, 'bind_result'), $params);
        if($stmt->fetch())
            return $result;
    }

    return null;
}

как вы можете видеть, он создает массив и извлекает его с данными строки, поскольку он используется $stmt->fetch()внутри, вы можете вызывать его так же, как вы бы вызывали mysqli_result::fetch_assoc(просто убедитесь, что $stmtобъект открыт и результат сохранен):

//mysqliConnection is your mysqli connection object
if($stmt = $mysqli_connection->prepare($query))
{
    $stmt->execute();
    $stmt->store_result();

    while($assoc_array = fetchAssocStatement($stmt))
    {
        //do your magic
    }

    $stmt->close();
}

Это самый простой способ замены. Сработало отлично - спасибо!
Alex Coleman

Сэкономил мне много времени!
Jahaziel

3
Если $statement->store_result();это необходимо перед вызовом функции, почему бы просто не включить ее в функцию?
InsanityOnABun

Спасибо. Только что спас мою задницу на крайнем сроке
Каньон Колоб

20

В PHP версии 7.2 я просто использовал nd_mysqli вместо mysqli, и он работал должным образом .

Шаги по включению его на сервер хостинга godaddy-

  1. Войдите в cpanel.
  2. Нажмите «Выбрать версию PHP» .
  3. В соответствии с приведенным снимком последних конфигураций снимите флажок «mysqli» и включите «nd_mysqli» .

введите описание изображения здесь


2
Спасибо, я с ума сошел!
Уссаид Икбал

1
Хааа, это экономит мое время! Спасибо, братан!
Нурул Худа

1
здорово! идеальный ответ для cPanel
Рашид

1
Огромное спасибо!! Ты спасешь меня, чувак, я не могу отблагодарить тебя достаточно,
Энес Чалишкан

Этот ответ должен быть на высоте
Ришаб Гусейн

10

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

Я хотел использовать метод get_results (), но у меня не было драйвера, и я не могу его добавить. Итак, прежде чем я позвонил

$stmt->bind_results($var1,$var2,$var3,$var4...etc);

Я создал пустой массив, а затем просто связал результаты как ключи в этом массиве:

$result = array();
$stmt->bind_results($result['var1'],$result['var2'],$result['var3'],$result['var4']...etc);

чтобы эти результаты можно было легко передать в методы или преобразовать в объект для дальнейшего использования.

Надеюсь, это поможет всем, кто хочет сделать что-то подобное.


7

Я получал ту же ошибку на своем сервере - PHP 7.0 с уже включенным расширением mysqlnd .

Решением для меня (благодаря этой странице ) было отменить выбор расширения mysqli и вместо этого выбрать nd_mysqli .

NB - Вы можете получить доступ к селектору расширений в cPanel. (Я получаю доступ к своей через опцию Select PHP Version .)


Это должен быть принятый ответ. Намного лучше включить расширение, чем редактировать весь сценарий, чтобы использовать другой метод! О, и это сработало для меня :)
ArabianMaiden

У меня такая же проблема. Фактически, использование session_start()функции PHP сделало меня несуществующим значением. Затем я обновился до версии 7.2PHP и изменил расширение mysqliна nd_mysqli (исправлено). Но у меня два вопроса: в чем разница между ними? и есть ли какие-либо пробелы в безопасности при использовании этого расширения?
jecorrales 04

6

Я понимаю, что уже давно не было никаких новых действий по этому вопросу. Но, как прокомментировали другие get_result()авторы, теперь это доступно только в PHP после установки собственного драйвера MySQL (mysqlnd), и в некоторых случаях установка mysqlnd может быть невозможной или нежелательной. Итак, я подумал, что было бы полезно опубликовать этот ответ с информацией о том, как получить предлагаемую функциональность get_result()- без использования get_result().

get_result()Часто используется в сочетании с, fetch_array()чтобы перебирать набор результатов и сохранять значения из каждой строки набора результатов в числовом индексе или ассоциативном массиве. Например, приведенный ниже код использует get_result () с fetch_array () для циклического просмотра набора результатов, сохраняя значения из каждой строки в массиве $ data [] с числовой индексацией:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$result = $stmt->get_result();       
while($data = $result->fetch_array(MYSQLI_NUM)) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

Однако, если get_result()он недоступен (поскольку mysqlnd не установлен), это приводит к проблеме того, как сохранить значения из каждой строки набора результатов в массиве без использования get_result(). Или как перенести устаревший код, который используется get_result()для работы без него (например, используяbind_result() вместо него), при этом как можно меньше влияя на остальную часть кода.

Оказывается, сохранение значений из каждой строки в массиве с числовым индексом не так просто использовать bind_result(). bind_result()ожидает список скалярных переменных (не массив). Итак, требуется некоторое усилие, чтобы заставить его сохранять значения из каждой строки набора результатов в массиве.

Конечно, код можно легко изменить следующим образом:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$stmt->bind_result($data[0], $data[1]);
while ($stmt->fetch()) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

Но это требует, чтобы мы явно перечисляли $ data [0], $ data [1] и т. Д. По отдельности в вызове bind_result(), что не идеально. Нам нужно решение, которое не требует от нас явного перечисления $ data [0], $ data [1], ... $ data [N-1] (где N - количество полей в операторе выбора) в звонке bind_results(). Если мы переносим устаревшее приложение с большим количеством запросов, и каждый запрос может содержать разное количество полей в selectпредложении, миграция будет очень трудоемкой и подвержена ошибкам, если мы будем использовать решение, подобное приведенному выше. .

В идеале нам нужен фрагмент кода «вставной замены» - чтобы заменить только строку, содержащую get_result()функцию и цикл while (), на следующей строке. Код замены должен иметь ту же функцию, что и код, который он заменяет, не затрагивая ни одну из строк до или любую из строк после, включая строки внутри цикла while (). В идеале мы хотим, чтобы код замены был как можно более компактным, и мы не хотим, чтобы код замены зависел от количества полей в selectпредложении запроса.

Поискав в Интернете, я нашел ряд решений, которые используются bind_param()с call_user_func_array() (например, динамически связывают параметры mysqli_stmt, а затем связывают результат (PHP) ), но большинство решений, которые я нашел, в конечном итоге приводят к тому, что результаты сохраняются в ассоциативном массиве, а не массив с числовой индексацией, и многие из этих решений были не такими компактными, как хотелось бы, и / или не подходили в качестве «заменяемых элементов». Однако из примеров, которые я нашел, я смог сколотить это решение, которое отвечает всем требованиям:

$c=1000;
$sql="select account_id, username from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);                 
$stmt->bind_param('i', $c);                                             
$stmt->execute();
$data=array();
for ($i=0;$i<$mysqli->field_count;$i++) { 
    $var = $i;
    $$var = null; 
    $data[$var] = &$$var; 
}
call_user_func_array(array($stmt,'bind_result'), $data);
while ($stmt->fetch()) {
   print $data[0] . ', ' . $data[1] . "<BR>\n"; 
}

Конечно, цикл for () можно свернуть в одну строку, чтобы сделать его более компактным.

Я надеюсь, что это поможет любому, кто ищет решение, использующее bind_result()для хранения значений из каждой строки в массиве с числовой индексацией и / или ищущий способ переноса устаревшего кода с использованием get_result(). Комментарии приветствуются.


ЮПП. Перешел на PDO 3 года назад. В любом случае спасибо.
Кумар Куш

5

Вот моя альтернатива. Он объектно-ориентированный и больше похож на mysql / mysqli.

class MMySqliStmt{
    private $stmt;
    private $row;

    public function __construct($stmt){
        $this->stmt = $stmt;
        $md = $stmt->result_metadata();
        $params = array();
        while($field = $md->fetch_field()) {
            $params[] = &$this->row[$field->name];
        }
        call_user_func_array(array($stmt, 'bind_result'), $params) or die('Sql Error');
    }

    public function fetch_array(){
        if($this->stmt->fetch()){
            $result = array();
            foreach($this->row as $k => $v){
                $result[$k] = $v;
            }
            return $result;
        }else{
            return false;
        }
    }

    public function free(){
        $this->stmt->close();
    }
}

Использование:

$stmt = $conn->prepare($str);
//...bind_param... and so on
if(!$stmt->execute())die('Mysql Query(Execute) Error : '.$str);
$result = new MMySqliStmt($stmt);
while($row = $result->fetch_array()){
    array_push($arr, $row);
    //for example, use $row['id']
}
$result->free();
//for example, use the $arr

2

Я написал две простые функции, которые предоставляют те же функциональные возможности, что и $stmt->get_result();, но не требуют драйвера mysqlnd.

Вы просто заменяете

$result = $stmt->get_result(); с участием $fields = bindAll($stmt);

и

$row= $stmt->get_result(); с $row = fetchRowAssoc($stmt, $fields); .

(Чтобы получить количество возвращенных строк, вы можете использовать $stmt->num_rows.)

Вам просто нужно поместить эти две функции, которые я написал, где-нибудь в вашем PHP-скрипте . (например, прямо внизу)

function bindAll($stmt) {
    $meta = $stmt->result_metadata();
    $fields = array();
    $fieldRefs = array();
    while ($field = $meta->fetch_field())
    {
        $fields[$field->name] = "";
        $fieldRefs[] = &$fields[$field->name];
    }

    call_user_func_array(array($stmt, 'bind_result'), $fieldRefs);
    $stmt->store_result();
    //var_dump($fields);
    return $fields;
}

function fetchRowAssoc($stmt, &$fields) {
    if ($stmt->fetch()) {
        return $fields;
    }
    return false;
}

Как это работает :

Мой код использует эту $stmt->result_metadata();функцию, чтобы выяснить, сколько и какие поля возвращаются, а затем автоматически привязывает полученные результаты к заранее созданным ссылкам. Работает как шарм!


Не знаю, почему он был отклонен. Он действительно работает очень хорошо - я использовал его во многих проектах.
Стефан С.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.