调用未定义的方法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();吗?
favouretti 2011年

请检查在这些变量$_POST['EmailID'], $_POST['SLA'], $_POST['Password']提交正确使用与POST方法的HTML表单
ajreal

@ajreal:变量已正确发布。我使用print_r($ _ POST)测试了它们。
库玛·库什

@favoretti:我尝试使用$ stmt = $ conn-> mysqli-> stmt_init(); 。仍然没有运气。
库玛·库什

我想提到的一件事是,我在其他地方使用了类似的代码,并且它们工作正常。
库玛·库什

Answers:


146

请阅读此方法的用户说明:

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

它需要mysqlnd驱动程序...如果未在您的网站空间中安装它,则必须使用BIND_RESULT&FETCH!

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

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


4
非常感谢。那行得通。余未注释的延长= php_mysqli_mysqlnd.dllphp.ini中 ; 并重新启动了Apache2.2和MySQL服务。我应该取消注释该行extension = php_mysqli_libmysql.dll吗?在另一页上,mysqlnd比libmysql快。另外,我可以期望在大多数流行的托管服务提供商上安装mysqlnd吗?
库玛·库什

1
stmt_init()仅在过程准备好的语句中才需要。所以你不需要它!看:链接至于libmysql:不知道。而且我不会指望托管提供商来安装mysqlnd.dll ……最好尝试一些解决方法!
2011年

2
注意:mysqli_stmt::get_result()仅在PHP v5.3.0或更高版本上可用。
猛禽

4
@bekay您刚刚为我保存了新笔记本电脑和新窗口。如果是可用的+10我给你这
詹姆斯库欣

1
@ kush.impetus,您在哪里下载php_mysqli_mysqlnd.dll?我只会 php_mysqli.dll在我的ext文件夹中。
Pacerier 2015年

51

因此,如果MySQL本机驱动程序(mysqlnd)驱动程序不可用,因此使用bind_resultfetch而不是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 2015年

2
问题:变量$ EmailVerfied来自何处?
Rotimi

@ Akintunde007:$EmailVerfied是通过调用创建的bind_result()
AbraCadaver

通过使用代码获得“未捕获的错误:调用未定义的方法mysqli_stmt :: bind_results()”错误
Devil's Dream

如果我有类似“从表名中选择*”的sql查询,那么如何在bind_result()中声明。*运营商
Inderjeet

46

您的系统缺少mysqlnd驱动程序!

如果您能够在(基于Debian / Ubuntu的)服务器上安装新软件包,请安装驱动程序:

sudo apt-get install php5-mysqlnd

然后重新启动您的Web服务器:

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

这是最简单的直接替换答案。很棒-谢谢!
亚历克斯·科尔曼

节省了我很多时间!
Jahaziel

3
如果$statement->store_result();在调用函数之前需要,为什么不将其包括在函数中呢?
InsanityOnABun

谢谢。只是在最后期限里救了我的屁股
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
非常感谢!!你救了我一个人,我感激
不尽

这个答案应该放在最上面
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

我在服务器上遇到了同样的错误-带有mysqlnd的 PHP 7.0已启用扩展的。

解决方案对我来说(感谢此页面)是取消选择mysqli扩展名并选择nd_mysqli而是。

注意:您也许可以访问cPanel中的扩展程序选择器。(我通过“ 选择PHP版本”选项访问我的。)


这应该是公认的答案。启用扩展比编辑整个脚本以使用另一种方法要好得多!哦,它对我
有用

我有同样的问题。实际上,使用PHP的session_start()函数使我像一个不存在的值。然后,我升级到7.2PHP 版本,并将扩展名更改 mysqlind_mysqli (固定)。但是,我有两个问题,两者有什么区别?使用该扩展程序在安全性方面是否存在任何差距?
jecorrales

6

我意识到距此问题已有一段时间,因此已有一段时间。但是,正如其他发布者所评论的那样- get_result()现在只能通过安装MySQL本机驱动程序(mysqlnd)在PHP中使用,在某些情况下,可能无法或不希望安装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子句中可能包含不同数量的字段,那么如果使用上述解决方案,则迁移将非常耗费劳力并且容易出错。

理想情况下,我们需要一段“直接替换”代码-仅替换包含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()。欢迎发表评论。


是的 3年前转为PDO。不管怎么说,多谢拉。
库玛·库什

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.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.