Wywołanie niezdefiniowanej metody mysqli_stmt :: get_result


113

Oto mój kod:

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();

Otrzymuję błąd w ostatnim wierszu jako: Wywołanie niezdefiniowanej metody mysqli_stmt :: get_result ()

Oto kod dla 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();
        }
    }
}

Jeśli napiszę ten wiersz:

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

Wyświetla komunikat „Oświadczenie NIE zostało przygotowane” . Jeśli uruchomię zapytanie bezpośrednio w IDE zastępując? oznacza wartościami, działa dobrze. Należy pamiętać, że obiekt $ conn działa dobrze w innych zapytaniach w projekcie.

Proszę o pomoc .......


Chyba zapomniałeś $stmt = $conn->mysqli->stmt_init();?
— favoretti

Sprawdź, czy te zmienne zostały $_POST['EmailID'], $_POST['SLA'], $_POST['Password']przesłane poprawnie za pomocą formularza HTML z metodą POST
— ajreal

@ajreal: Zmienne są wysyłane poprawnie. Przetestowałem je używając print_r ($ _ POST).
— Kumar Kush

@favoretti: Próbowałem użyć $ stmt = $ conn-> mysqli-> stmt_init (); . Wciąż nie ma szczęścia.
— Kumar Kush

Jedną rzeczą, o której chciałbym wspomnieć, jest to, że użyłem podobnego kodu w innych miejscach i działają dobrze.
— Kumar Kush

Odpowiedzi:


146

Przeczytaj uwagi użytkownika dotyczące tej metody:

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

Wymaga sterownika mysqlnd ... jeśli nie jest zainstalowany na Twojej przestrzeni internetowej, będziesz musiał pracować z 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
Wielkie dzięki. To się udało. I Odkomentowano się extension = php_mysqli_mysqlnd.dll w php.ini ; i zrestartowałem usługi Apache2.2 i MySQL. Czy powinienem odkomentować rozszerzenie linii = php_mysqli_libmysql.dll ? Jak na innej stronie, mysqlnd jest szybszy niż libmysql. Czy mogę się spodziewać zainstalowania mysqlnd u najpopularniejszych dostawców usług hostingowych?
— Kumar Kush

1
Funkcja stmt_init () jest potrzebna tylko w przypadku instrukcji przygotowanej zgodnie z procedurą. więc nie potrzebujesz tego! Zobacz: link Co do libmysql : nie wiem. I nie liczyłbym na dostawców usług hostingowych do instalacji mysqlnd.dll ... lepiej spróbuj obejścia!
— bekay

2
Uwaga: mysqli_stmt::get_result()jest dostępne tylko w wersji PHP 5.3.0 lub nowszej.
— Raptor

4
@bekay Właśnie zapisałeś mi nowego laptopa i nowe okno. Gdyby był dostępny +10, dałbym ci go
— James Cushing

1
@ kush.impetus, skąd pobierasz php_mysqli_mysqlnd.dll? Miałbym tylko php_mysqli.dllw swoim extfolderze.
— Pacerier

51

Więc jeśli sterownik MySQL Native Driver (mysqlnd) nie jest dostępny, a zatem używając bind_result i fetch zamiast get_result , kod wygląda następująco:

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 oszczędza mój czas. Jest to świetne rozwiązanie, gdy get_result nie jest dostępne.
— Zafer

2
pytanie: skąd pochodzi zmienna $ EmailVerfied?
— Rotimi

@ Akintunde007: $EmailVerfiedjest tworzony przez wywołanie bind_result().
— AbraCadaver

Pojawia się błąd „Uncaught Error: Call to undefined method mysqli_stmt :: bind_results ()” przez użycie kodu
— Devil's Dream

Jeśli mam zapytanie sql, takie jak „Wybierz * z nazwa_tabeli”, to jak zadeklarować wewnątrz bind_result (). * operator
— Inderjeet,

46

W Twoim systemie brakuje sterownika mysqlnd!

Jeśli możesz zainstalować nowe pakiety na swoim serwerze (opartym na Debianie / Ubuntu), zainstaluj sterownik:

sudo apt-get install php5-mysqlnd

a następnie zrestartuj serwer WWW:

sudo /etc/init.d/apache2 restart

39

dla tych, którzy szukają alternatywy dla $result = $stmt->get_result()stworzyłem tę funkcję, która pozwala naśladować, $result->fetch_assoc()ale używając bezpośrednio obiektu 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;
}

jak widać, tworzy tablicę i pobiera ją z danymi wiersza, ponieważ używa $stmt->fetch()wewnętrznie, możesz ją wywołać tak, jak byś wywołała mysqli_result::fetch_assoc(tylko upewnij się, że $stmtobiekt jest otwarty, a wynik jest zapisany):

//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();
}

To jest najłatwiejsza odpowiedź zastępcza typu drop-in. Działało świetnie - dzięki!
— Alex Coleman,

Zaoszczędziłeś mi dużo czasu!
— Jahaziel

3
Jeśli $statement->store_result();jest to konieczne przed wywołaniem funkcji, dlaczego po prostu nie uwzględnić jej w funkcji?
— InsanityOnABun

Dziękuję Ci. Właśnie uratowałem mój tyłek w terminie
— Kolob Canyon

20

W wersji PHP 7.2 użyłem tylko nd_mysqli zamiast mysqli i wszystko działało zgodnie z oczekiwaniami.

Kroki, aby włączyć go do serwera hostingowego GoDaddy-

  1. Zaloguj się do cpanel.
  2. Kliknij „Wybierz wersję PHP” .
  3. Zgodnie z zapisem stanu najnowszych konfiguracji odznacz „mysqli” i włącz „nd_mysqli” .

wprowadź opis obrazu tutaj


2
Dziękuję, oszalałem!
— Ussaid Iqbal

1
Haaa, to oszczędza mi czas! Dziękuję brachu!
— Nurul Huda

1
świetny! doskonała odpowiedź dla cPanel
— Rashid

1
Dziękuję bardzo!! Ocal mnie stary, nie mogę ci wystarczająco podziękować
— Enes Çalışkan

Ta odpowiedź powinna być na topie
— Rishabh Gusain

10

Wiem, że już udzielono odpowiedzi na temat tego, jaki jest rzeczywisty problem, jednak chcę zaproponować proste obejście.

Chciałem użyć metody get_results (), ale nie miałem sterownika i nie jestem gdzieś, gdzie mogę to dodać. Więc zanim zadzwoniłem

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

Utworzyłem pustą tablicę, a następnie powiązałem wyniki jako klucze w tej tablicy:

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

aby te wyniki można było łatwo przekazać do metod lub rzutować na obiekt w celu dalszego wykorzystania.

Mam nadzieję, że pomoże to każdemu, kto chce zrobić coś podobnego.


7

Otrzymałem ten sam błąd na moim serwerze - PHP 7.0 z już włączonym rozszerzeniem mysqlnd .

Rozwiązaniem było dla mnie (dzięki tej stronie ) odznaczenie rozszerzenia mysqli i zamiast tego wybranie nd_mysqli .

NB - Możesz mieć dostęp do selektora rozszerzeń w swoim cPanel. (Mam dostęp do mojego poprzez opcję Wybierz wersję PHP ).


To powinna być akceptowana odpowiedź. O wiele lepiej jest włączyć rozszerzenie niż edytować cały skrypt w celu użycia innej metody! Aha i to u mnie zadziałało :)
— ArabianMaiden

Miałem ten sam problem. W rzeczywistości użycie session_start()funkcji PHP sprawiło, że poczułem się jak nieistniejąca wartość. Następnie zaktualizowałem do wersji 7.2PHP i zmieniłem rozszerzenie mysqlina nd_mysqli (naprawione). Ale mam dwa pytania, jaka jest różnica między nimi? i czy byłaby jakaś luka w bezpieczeństwie korzystania z tego rozszerzenia?
— jecorrales

6

Zdaję sobie sprawę, że minęło trochę czasu, odkąd pojawiły się nowe działania w tej kwestii. Ale, jak komentowali inni plakaty - get_result()jest teraz dostępny tylko w PHP po zainstalowaniu natywnego sterownika MySQL (mysqlnd), aw niektórych przypadkach może nie być możliwe lub pożądane zainstalowanie mysqlnd. Pomyślałem więc, że pomocne byłoby opublikowanie tej odpowiedzi z informacjami o tym, jak uzyskać oferowaną funkcjonalność get_result()- bez użycia get_result().

get_result()jest / był często łączony z, fetch_array()aby zapętlić zestaw wyników i przechowywać wartości z każdego wiersza zestawu wyników w tablicy indeksowanej numerycznie lub asocjacyjnej. Na przykład poniższy kod wykorzystuje metodę get_result () z funkcją fetch_array () do przechodzenia przez zestaw wyników, przechowując wartości z każdego wiersza w tablicy $ data [] indeksowanej numerycznie:

$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"; 
}

Jeśli jednak get_result()nie jest dostępny (ponieważ mysqlnd nie jest zainstalowany), prowadzi to do problemu z przechowywaniem wartości z każdego wiersza zestawu wyników w tablicy bez użycia get_result(). Albo jak przeprowadzić migrację starszego kodu, get_result()który działa bez niego (np. Używając bind_result()zamiast tego) - przy jak najmniejszym wpływie na resztę kodu.

Okazuje się, że przechowywanie wartości z każdego wiersza w tablicy indeksowanej numerycznie nie jest tak proste w użyciu bind_result(). bind_result()oczekuje listy zmiennych skalarnych (nie tablicy). Tak więc wymaga trochę pracy, aby przechowywać wartości z każdego wiersza zestawu wyników w tablicy.

Oczywiście kod można łatwo zmodyfikować w następujący sposób:

$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"; 
}

Ale to wymaga od nas, abyśmy w wywołaniu funkcji wyraźnie wymieniali $ data [0], $ data [1] itd. bind_result(), Co nie jest idealne. Chcemy rozwiązania, które nie wymaga od nas jawnej listy $ data [0], $ data [1], ... $ data [N-1] (gdzie N to liczba pól w instrukcji select) w wezwaniu do bind_results(). Jeśli przeprowadzamy migrację starszej aplikacji, która ma dużą liczbę zapytań, a każde zapytanie może zawierać inną liczbę pól w selectklauzuli, migracja będzie bardzo pracochłonna i podatna na błędy, jeśli użyjemy rozwiązania takiego jak powyższe .

Idealnie byłoby, gdybyśmy potrzebowali fragmentu kodu „zastępującego wstawianie” - aby zastąpić tylko wiersz zawierający get_result()funkcję i pętlę while () w następnym wierszu. Kod zastępczy powinien mieć taką samą funkcję jak kod, który zastępuje, bez wpływu na żadną z wierszy przed ani na wiersze po - w tym wiersze wewnątrz pętli while (). W idealnym przypadku chcemy, aby kod zastępczy był możliwie jak najbardziej zwarty i nie chcemy modyfikować kodu zastępczego na podstawie liczby pól w selectklauzuli zapytania.

Szukając w Internecie, znalazłem szereg rozwiązań, które używają bind_param()z call_user_func_array() (na przykład Dynamiczne wiązanie parametrów mysqli_stmt, a następnie wiązanie wyniku (PHP) ), ale większość rozwiązań, które znalazłem, ostatecznie prowadzi do przechowywania wyników w tablicy asocjacyjnej, a nie tablica indeksowana numerycznie, a wiele z tych rozwiązań nie było tak zwartych, jak bym chciał i / lub nie nadawało się jako „zamienniki typu drop-in”. Jednak z przykładów, które znalazłem, udało mi się zebrać razem to rozwiązanie, które pasuje do rachunku:

$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"; 
}

Oczywiście pętlę for () można zwinąć w jedną linię, aby była bardziej zwarta.

Mam nadzieję, że pomoże to każdemu, kto szuka rozwiązania używającego bind_result()do przechowywania wartości z każdego wiersza w tablicy indeksowanej numerycznie i / lub szukającego sposobu na migrację starszego kodu przy użyciu get_result(). Komentarze mile widziane.


Tak. Przeniesione do ChNP 3 lata temu. W każdym razie dzięki.
— Kumar Kush,

5

Oto moja alternatywa. Jest zorientowany obiektowo i bardziej przypomina rzeczy 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();
    }
}

Stosowanie:

$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

Napisałem dwie proste funkcje, które dają taką samą funkcjonalność jak $stmt->get_result();, ale nie wymagają sterownika mysqlnd.

Po prostu wymieniasz

$result = $stmt->get_result(); z $fields = bindAll($stmt);

i

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

(Aby uzyskać liczbę zwróconych wierszy, których możesz użyć $stmt->num_rows).

Musisz tylko umieścić te dwie funkcje , które napisałem gdzieś w swoim skrypcie PHP . (na przykład na dole)

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;
}

Jak to działa :

Mój kod używa tej $stmt->result_metadata();funkcji, aby dowiedzieć się, ile i które pola są zwracane, a następnie automatycznie wiąże pobrane wyniki z wstępnie utworzonymi odwołaniami. Działa jak marzenie!


Nie mam pojęcia, dlaczego został odrzucony. Działa bardzo dobrze - używałem go w wielu projektach.
— Stefan S.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.