เรียกวิธีการที่ไม่ได้กำหนด 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();

ฉันได้รับข้อผิดพลาดในบรรทัดสุดท้ายเป็น: Call to undefined method 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)
Kumar Kush

@favoretti: ฉันลองใช้$ stmt = $ conn-> mysqli-> stmt_init (); . ยังไม่มีโชค
Kumar Kush

สิ่งหนึ่งที่ฉันอยากจะพูดถึงคือฉันเคยใช้รหัสที่คล้ายกันคือที่อื่นและใช้งานได้ดี
Kumar Kush

คำตอบ:


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
ขอบคุณมาก. ที่ได้ผล ฉันไม่ใส่ความคิดเห็นส่วนขยาย = php_mysqli_mysqlnd.dllในphp.ini ; และเริ่มบริการ Apache2.2 และ MySQL ใหม่ ฉันควรยกเลิกการใส่ข้อคิดเห็นส่วนขยายบรรทัด= php_mysqli_libmysql.dllหรือไม่ ตามหน้าอื่น mysqlnd เร็วกว่า libmysql นอกจากนี้ฉันสามารถคาดหวังว่า mysqlnd จะติดตั้งบนผู้ให้บริการโฮสติ้งยอดนิยมส่วนใหญ่ได้หรือไม่?
Kumar Kush

1
stmt_init ()จำเป็นสำหรับคำสั่งที่เตรียมขั้นตอนเท่านั้น ดังนั้นคุณไม่จำเป็นต้องใช้! ดู: ลิงค์สำหรับlibmysql : ไม่รู้ และฉันจะไม่พึ่งพาผู้ให้บริการโฮสติ้งสำหรับการติดตั้งmysqlnd.dll ... ดีกว่าลองวิธีแก้ปัญหา!
bekay

2
หมายเหตุ: mysqli_stmt::get_result()ใช้ได้เฉพาะใน PHP v5.3.0 ขึ้นไป
Raptor

4
@bekay คุณเพิ่งบันทึกแล็ปท็อปเครื่องใหม่และหน้าต่างใหม่ให้ฉัน ถ้ามี +10 ฉันจะให้
James Cushing

1
@ kush.impetus คุณดาวน์โหลดphp_mysqli_mysqlnd.dllที่ไหน ฉันมี php_mysqli.dllอยู่ในextโฟลเดอร์เท่านั้น
Pacerier

51

ดังนั้นหากไม่มีไดรเวอร์ MySQL Native Driver (mysqlnd) ดังนั้นจึงใช้bind_resultและดึงข้อมูลแทน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

รับข้อผิดพลาด "Uncaught Error: Call to undefined method mysqli_stmt :: bind_results ()" โดยใช้รหัส
Devil's Dream

ถ้าฉันมีแบบสอบถาม sql เช่น "เลือก * จาก table_name" แล้วจะประกาศภายใน bind_result () ได้อย่างไร * operator
Inderjeet

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();จำเป็นก่อนเรียกใช้ฟังก์ชันทำไมไม่รวมไว้ในฟังก์ชัน?
InsanityOnAB

ขอบคุณ. เพิ่งช่วยลาของฉันตามกำหนดเวลา
Kolob Canyon

20

ด้วย PHP เวอร์ชัน 7.2 ฉันเพิ่งใช้nd_mysqliแทนmysqliและทำงานได้ตามที่คาดไว้

ขั้นตอนในการเปิดใช้งานในเซิร์ฟเวอร์โฮสติ้งของ GoDaddy -

  1. เข้าสู่ระบบ cpanel
  2. คลิกที่"เลือก PHP รุ่น"
  3. ให้เป็นภาพรวมของการกำหนดค่าที่ล่าสุดยกเลิกการเลือก"mysqli"และเปิดใช้งาน"nd_mysqli"

ใส่คำอธิบายภาพที่นี่


2
ขอบคุณฉันจะบ้า!
Ussaid Iqbal

1
ฮ่าฮ่านี่ช่วยประหยัดเวลาของฉัน! ขอบคุณครับ!
Nurul Huda

1
ที่ดี! คำตอบที่สมบูรณ์แบบสำหรับ cPanel
Rashid

1
ขอบคุณมาก!! คุณช่วยฉันด้วยฉันไม่สามารถขอบคุณคุณได้มากพอ
Enes Çalışkan

คำตอบนี้ควรอยู่ด้านบน
Rishabh Gusain

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แทน

หมายเหตุ - คุณอาจสามารถเข้าถึงตัวเลือกส่วนขยายใน cPanel ของคุณได้ (ฉันเข้าถึงของฉันผ่านตัวเลือกเลือกเวอร์ชัน PHP )


นี่ควรเป็นคำตอบที่ได้รับการยอมรับ เปิดใช้งานส่วนขยายได้ดีกว่าการแก้ไขสคริปต์ทั้งหมดของคุณเพื่อใช้วิธีอื่น! โอ้และได้ผลสำหรับฉัน :)
ArabianMaiden

ผมมีปัญหาเหมือนกัน. ในความเป็นจริงการใช้session_start()ฟังก์ชันของ PHP ทำให้ฉันเป็นเหมือนค่าที่ไม่มีอยู่จริง จากนั้นฉันอัปเกรดเป็นเวอร์ชัน7.2ของ PHP และเปลี่ยนนามสกุล mysqliเป็นnd_mysqli (แก้ไขแล้ว) แต่ฉันมีคำถามสองข้อความแตกต่างระหว่างสองข้อนี้คืออะไร? และจะมีช่องว่างในการรักษาความปลอดภัยสำหรับการใช้ส่วนขยายนั้นหรือไม่?
jecorrales

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 คือจำนวนฟิลด์ในคำสั่ง select) bind_results()ในการเรียกร้องให้ หากเรากำลังโอนย้ายแอปพลิเคชันเดิมที่มีข้อความค้นหาจำนวนมากและแต่ละคำค้นหาอาจมีฟิลด์จำนวนแตกต่างกันในส่วนselectคำสั่งการย้ายข้อมูลจะใช้แรงงานมากและมีแนวโน้มที่จะเกิดข้อผิดพลาดหากเราใช้วิธีแก้ปัญหาเช่นเดียวกับด้านบน .

ตามหลักการแล้วเราต้องการข้อมูลโค้ด 'drop-in replacement' - เพื่อแทนที่เฉพาะบรรทัดที่มี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()หรือมองหาวิธีการโยกย้ายรหัสเดิมที่ใช้ ยินดีต้อนรับความคิดเห็น


yupp เปลี่ยนเป็น PDO เมื่อ 3 ปีที่แล้ว ขอบคุณทุกวิธี
Kumar Kush

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();ฟังก์ชันเพื่อหาจำนวนและเขตข้อมูลที่จะส่งคืนจากนั้นเชื่อมโยงผลลัพธ์ที่ดึงเข้ากับการอ้างอิงที่สร้างไว้ล่วงหน้าโดยอัตโนมัติ ใช้งานได้เหมือนมีเสน่ห์!


ไม่รู้ว่าทำไมถึงถูกลดคะแนน มันทำงานได้ดีมาก - ฉันใช้มันในหลายโครงการ
Stefan S.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.