调用未定义的方法 mysqli_stmt::get_result

Posted

技术标签:

【中文标题】调用未定义的方法 mysqli_stmt::get_result【英文标题】:Call to undefined method mysqli_stmt::get_result 【发布时间】:2022-01-11 20:28:30 【问题描述】:

这是我的代码:

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

它打印出'Statement NOT prepare'。如果我直接在 IDE 中运行查询替换?带有值的标记,它工作正常。请注意 $conn 对象在项目中的其他查询中工作正常。

请帮忙.......

【问题讨论】:

我想你忘了$stmt = $conn->mysqli->stmt_init(); 请检查这些变量$_POST['EmailID'], $_POST['SLA'], $_POST['Password']是否使用带有POST方法的html表单正确提交 @ajreal:变量已正确发布。我使用 print_r($_POST) 对它们进行了测试。 @favoretti:我尝试使用 $stmt = $conn->mysqli->stmt_init();。还是没有运气。 我想提一提的是,我在其他地方使用过类似的代码,它们工作正常。 【参考方案1】:

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

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

它需要 mysqlnd 驱动程序...如果您的网站空间上没有安装它,您将不得不使用 bind_result()fetch()

【讨论】:

非常感谢。那行得通。我取消了 php.ini 中的 extension=php_mysqli_mysqlnd.dll 的注释;并重新启动 Apache2.2 和 MySQL 服务。我应该取消注释 extension=php_mysqli_libmysql.dll 行吗?根据另一页,mysqlnd 比 libmysql 快。另外,我可以期望在大多数流行的托管服务提供商上安装 mysqlnd 吗? stmt_init() 仅用于程序准备语句。所以你不需要它!看:link 至于libmysql:不知道。而且我不会指望托管服务提供商来安装 mysqlnd.dll ...最好尝试一些解决方法! 注意:mysqli_stmt::get_result() 仅适用于 PHP v5.3.0 或更高版本。 @bekay 你刚刚为我保存了一台新笔记本电脑和一个新窗口。如果 +10 可用,我会给你它 @kush.impetus,你在哪里下载php_mysqli_mysqlnd.dll?我的ext 文件夹中只有php_mysqli.dll【参考方案2】:

所以如果 MySQL Native Driver (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 不可用时,这是一个很好的解决方案。 问题:变量 $EmailVerfied 来自哪里? @Akintunde007: $EmailVerfied 是通过调用bind_result() 创建的。 使用代码获取“未捕获的错误:调用未定义的方法 mysqli_stmt::bind_results()”错误 如果我有像“Select * from table_name”这样的 sql 查询,那么如何在 bind_result() 中声明。 * 运算符【参考方案3】:

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

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

sudo apt-get install php5-mysqlnd

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

sudo /etc/init.d/apache2 restart

【讨论】:

【参考方案4】:

我知道这已经回答了实际问题是什么,但是我想提供一个简单的解决方法。

我想使用 get_results() 方法,但是我没有驱动程序,而且我无法添加它。所以,在我打电话之前

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

我创建了一个空数组,然后将结果绑定为该数组中的键:

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

这样这些结果就可以很容易地传递给方法或转换为对象以供进一步使用。

希望这可以帮助任何想要做类似事情的人。

【讨论】:

【参考方案5】:

对于那些寻找$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();

【讨论】:

如果在调用函数之前需要$statement->store_result();,为什么不把它包含在函数中呢?【参考方案6】:

这是我的替代方案。它是面向对象的,更像是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

【讨论】:

【参考方案7】:

我意识到已经有一段时间没有关于这个问题的任何新活动了。但是,正如其他发帖人所评论的那样 - 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"; 

但是,这需要我们在对bind_result() 的调用中单独显式列出$data[0]、$data[1] 等,这并不理想。我们想要一个不需要我们显式列出 $data[0], $data[1], ... $data[N-1] 的解决方案(其中 N 是 select 语句中的字段数)在对bind_results() 的调用中。如果我们正在迁移具有大量查询的遗留应用程序,并且每个查询可能在select 子句中包含不同数量的字段,那么如果我们使用类似的解决方案,迁移将非常耗费人力并且容易出错上面那个。

理想情况下,我们需要一个“插入式替换”代码的 sn-p - 仅替换包含 get_result() 函数的行和下一行的 while() 循环。替换代码应该与它正在替换的代码具有相同的功能,而不影响之前的任何行或之后的任何行 - 包括 while() 循环内的行。理想情况下,我们希望替换代码尽可能紧凑,并且我们不希望根据查询的select 子句中的字段数来定制替换代码。

在互联网上搜索,我发现了许多使用bind_param()call_user_func_array() 的解决方案 (例如,Dynamically bind mysqli_stmt parameters and then bind result (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。感谢任何方式。【参考方案8】:

我编写了两个简单的函数,它们提供与$stmt-&gt;get_result(); 相同的功能,但它们不需要 mysqlnd 驱动程序。

您只需替换

$result = $stmt-&gt;get_result(); $fields = bindAll($stmt);

$row= $stmt-&gt;get_result(); $row = fetchRowAssoc($stmt, $fields);.

(要获取返回的行数,您可以使用$stmt-&gt;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-&gt;result_metadata(); 函数来确定返回了多少和哪些字段,然后自动将获取的结果绑定到预先创建的引用。像魅力一样工作!

【讨论】:

不知道为什么它被否决了。它确实工作得很好——我在很多项目中都使用过它。【参考方案9】:

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

对我来说解决方案(感谢this page)是取消选择 mysqli 扩展并选择 nd_mysqli

注意 - 您也许可以在您的 cPanel 中访问扩展选择器。 (我通过 Select PHP Version 选项访问我的。)

【讨论】:

这应该是公认的答案。启用扩展比编辑整个脚本以使用另一种方法要好得多!哦,它对我有用:) 我遇到了同样的问题。事实上,使用 PHP 的session_start() 函数让我感觉像是一个不存在的价值。然后我升级到PHP的7.2版本,将mysqli的扩展名改为nd_mysqli (fixed)。但是,我有两个问题,两者有什么区别?使用该扩展程序是否存在安全漏洞?【参考方案10】:

在 PHP 7.2 版中,我只使用了 nd_mysqli 而不是 mysqli,它按预期工作。

将其启用到 Godaddy 托管服务器的步骤-

    登录到 cpanel。 点击“选择PHP版本”。 根据提供的最新配置快照,取消选中 "mysqli" 并启用 "nd_mysqli"

【讨论】:

谢谢你,我快疯了! 哈哈,这节省了我的时间!谢谢兄弟! 太棒了! cPanel 的完美答案 非常感谢!!你救了我,我感激不尽 这个答案应该在上面

以上是关于调用未定义的方法 mysqli_stmt::get_result的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 调用未定义的方法。方法存在

调用未定义的方法 App\Models\Catering::search() [关闭]

调用未定义的方法 BelongsTo::attach()

未调用自定义 UIButton 的 setIsSelected 方法

调用未定义的方法 Cake\ORM\Entity::query() CakePhp

致命错误:未捕获的错误:调用未定义的方法 stdClass::option();