在从数据库获取设置的函数上,我遇到了错误[duplicate]

On a function that gets settings from a DB I ran into the error [duplicate]

提问人:sushibrain 提问时间:12/10/2014 最后编辑:Dharmansushibrain 更新时间:12/6/2022 访问量:331172

问:

我正忙于一个从数据库获取设置的函数,突然,我遇到了这个错误:

Fatal error: Call to a member function bind_param() on boolean in C:\xampp2\htdocs\application\classes\class.functions.php on line 16

通常,这意味着我正在从不存在的表和东西中选择东西。但在这种情况下,我不是......

函数如下:getSetting

public function getSetting($setting)
{
    $query = $this->db->conn->prepare('SELECT value, param FROM ws_settings WHERE name = ?');
    $query->bind_param('s', $setting);
    $query->execute();
    $query->bind_result($value, $param);
    $query->store_result();
    if ($query->num_rows() > 0)
    {
        while ($query->fetch()) 
        {
            return $value;
            if ($param === '1')
            {
                $this->tpl->createParameter($setting, $value);
            }
        }
    }
    else
    {
        __('invalid.setting.request', $setting);
    }
}

变量通过构造函数传递。如果需要,这里是:$this->db

public function __construct($db, $data, $tpl)
{
    $this->db = $db;
    $this->tpl = $tpl;
    $this->data = $data;
    $this->data->setData('global', 'theme', $this->getSetting('theme'));
}

另外,由于我正在使用数据库,因此我的数据库连接:

class Database
{
    private $data;

    public function __construct($data)
    {
    $this->data = $data;
    $this->conn = new MySQLi(
      $this->data->getData('database', 'hostname'), 
      $this->data->getData('database', 'username'), 
      $this->data->getData('database', 'password'), 
      $this->data->getData('database', 'database')
    );
    if ($this->conn->errno)
    {
        __('failed.db.connection', $this->conn->errno);
    }
    date_default_timezone_set('Europe/Amsterdam');
}

我已经测试了连接,100% 肯定它按预期工作。 我正在配置文件中设置数据库连接:

'database' => array(
    'hostname' => '127.0.0.1',
    'username' => 'root',
    'password' => ******,
    'database' => 'wscript'
)

现在奇怪的是;表存在,请求的设置存在,数据库存在,但该错误仍然不会消失。以下是数据库正确的一些证据:

IMG

PHP MySQLI

答:

171赞 RobP 12/10/2014 #1

问题在于:

$query = $this->db->conn->prepare('SELECT value, param FROM ws_settings WHERE name = ?');
$query->bind_param('s', $setting);

prepare() 方法可以返回,您应该检查一下。至于为什么会返回,也许表名或列名(in或子句)不正确?falsefalseSELECTWHERE

此外,请考虑使用 $this->db->conn->error_list 之类的工具来检查解析 SQL 时发生的错误。(我偶尔会回显实际的 SQL 语句字符串并粘贴到 phpMyAdmin 中进行测试,但那里肯定有一些失败的地方。

评论

5赞 Adam 5/11/2016
当出现错误时,如果prepare方法返回false(因此$query将是false?),为什么建议调用?$query->error_list
2赞 RobP 12/13/2016
@Adam你说得有道理。如果bind_param或执行失败,则调用是有意义的,但如果是 false,则应该在 mysqli 对象上调用 或,即 .$query->error_list$queryerrorerror_list$this->db->conn->error_list
0赞 Mateusz H. 8/15/2019
当我遇到这个问题时,我从SQL查询中删除了“(”。上一个是“SELECT (user_id, price) FROM 操作,其中 user_id = 1。正确的版本是“SELECT user_id, price FROM ...当我删除“()”时,我摆脱了这个错误。
0赞 Sriram Nadiminti 5/6/2021
这个错误是相当误导的。与其他语言不同,没有指出根本原因。当错误是由第一行“prepare”引起的时,抛出的错误表明“bind_param”是原因。库多斯!!
12赞 meda 12/10/2014 #2

prepare因此,仅在失败时返回布尔值,为了避免错误,您需要在执行之前检查它是否是第一个:FALSETrue

$sql = 'SELECT value, param FROM ws_settings WHERE name = ?';
if($query = $this->db->conn->prepare($sql)){
    $query->bind_param('s', $setting);
    $query->execute();
    //rest of code here
}else{
   //error !! don't go further
   var_dump($this->db->error);
}
44赞 Jay Blanchard 8/6/2015 #3

任何时候你得到...

“致命错误:在布尔值上调用成员函数 bind_param()”

...这可能是因为您的查询存在问题。可能会返回(布尔值),但这个通用的失败消息不会给你留下太多线索。你如何发现你的查询有什么问题?你prepare()FALSE

首先,确保错误报告已打开且可见:在开始标记之后,将以下两行添加到文件顶部:<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);

如果您的错误报告已在php.ini中设置,则不必担心这一点。只要确保你优雅地处理错误,永远不要向用户透露任何问题的真正原因。向公众揭示真正原因可能是那些想要损害您的网站和服务器的人的金刻邀请。如果您不想向浏览器发送错误,您可以随时监控 Web 服务器错误日志。日志位置因服务器而异,例如,在 Ubuntu 上,错误日志通常位于 .如果要检查 Linux 环境中的错误日志,则可以在控制台窗口中查看实时发生的错误。或者当你制作它们时。/var/log/apache2/error.logtail -f /path/to/log

一旦你掌握了标准错误报告,在数据库连接和查询上添加错误检查将为你提供有关正在发生的问题的更多详细信息。请看这个列名不正确的示例。首先,返回一般致命错误消息的代码:

$sql = "SELECT `foo` FROM `weird_words` WHERE `definition` = ?";
$query = $mysqli->prepare($sql)); // assuming $mysqli is the connection
$query->bind_param('s', $definition);
$query->execute();

该错误是通用的,对您解决正在发生的事情不是很有帮助。

通过多几行代码,您可以获得非常详细的信息,您可以使用这些信息立即解决问题。检查声明的真实性,如果是好的,您可以继续绑定和执行。prepare()

$sql = "SELECT `foo` FROM `weird_words` WHERE `definition` = ?";
if($query = $mysqli->prepare($sql)) { // assuming $mysqli is the connection
    $query->bind_param('s', $definition);
    $query->execute();
    // any additional code you need would go here.
} else {
    $error = $mysqli->errno . ' ' . $mysqli->error;
    echo $error; // 1054 Unknown column 'foo' in 'field list'
}

如果出现问题,您可以吐出一条错误消息,直接将您带到问题所在。在这种情况下,表中没有列,解决问题是微不足道的。foo

如果选择,可以将此检查包含在函数或类中,并通过如前所述正常处理错误来扩展它。

评论

5赞 David Ferenczy Rogožan 11/28/2015
非常好的答案,主要是关于错误报告的建议。在禁用错误报告的情况下进行编程就像闭着眼睛下棋一样。人们也不知道如何使用调试器(或者它确实存在)。
1赞 Kerim Yagmurcu 3/17/2019
感谢您的出色工作,这对布兰查德@Jay非常有帮助
0赞 Nabi K.A.Z. 6/20/2019
但是错误是致命错误并死亡并停止了程序,因此关闭显示错误不能是很好的解决方案。
0赞 Shaedo 8/3/2019
此外,请检查您的用户对数据库的权限。如果说你的用户无法进行更新,那么你会得到这个错误,但上面的(非常好的答案)可能不会发现这个错误。
23赞 Tamas Kalman 5/24/2017 #4

即使查询语法正确,如果存在上一条语句并且未关闭,prepare 也可能返回 false。 始终用

$statement->close();

如果语法正确,则以下查询也将运行良好。

1赞 4ndyG 9/22/2017 #5

可能导致此问题的另一种情况是查询中的转换不正确。

我知道这听起来可能很明显,但我通过使用而不是 .检查查询,并确保使用与表中列的实际名称相同的大小写。tablenameTablename

5赞 Reejesh PK 2/17/2018 #6

有时,这也是因为 prepare 语句中的表名或列名错误

这个

评论

1赞 Reid Svntn 11/10/2020
这是我的问题,错误的表名!希望我早点看到这条评论!
1赞 Sam Banana 3/27/2018 #7

你应该总是尽可能地把你的语句放在一个trycatch块中......在这种情况下,它总是会有所帮助,并让您知道出了什么问题。也许表名或列名是错误的。

0赞 Sam Saarian 3/31/2018 #8

此特定错误与实际错误关系不大。这是我的类似经历和解决方案......

我有一个表,我在我的语句中使用了复合名称。我认为这不会有问题。这确实是问题所在。将其括在方括号内解决了我的问题()。所以,问题是MySQL保留了字(相反)......确保您的列也不会出现此类错误情况...|database-name|.login[|database-name|].[login]

2赞 Hari Das 5/2/2018 #9

以下两个是此问题最可能的原因:

  1. 列名或表名中的拼写错误
  2. 以前建立的语句不会关闭。只需在进行准备好的语句之前关闭它即可。

$stmt->close(); // <<<-----This fixed the issue for me

$stmt = $conn->prepare("Insert statement");
0赞 Ebite Zion 5/21/2018 #10

有时,显式说明表列名称(尤其是在插入查询中)可能会有所帮助。例如,查询:

INSERT INTO tableName(param1, param2, param3) VALUES(?, ?, ?)

与以下情况相比,可能效果更好:

INSERT INTO tableName VALUES(?, ?, ?)
1赞 Chrisogonas Odero Mc'Odhiambo 2/28/2019 #11

我注意到错误是由我将表字段名称作为变量传递引起的,即我发送了:

$stmt = $this->con->prepare("INSERT INTO tester ($test1, $test2) VALUES (?, ?)");

而不是:

$stmt = $this->con->prepare("INSERT INTO tester (test1, test2) VALUES (?, ?)");

请注意表字段名称包含在字段名称之前。他们不应该在那里,所以应该.$$field1field1

1赞 Sangeeth Arulraj 1/18/2020 #12

根据我的经验,这很好,但我弄错了数据库名称,所以,我只更改了连接参数中的数据库名称,它运行良好。bind_param

我已经定义了根路径来指示根文件夹,包括包含文件夹的路径和网站主URL的基本URL。这将用于在需要它们的地方调用它们。

评论

0赞 moh80s 1/18/2020
请提供一些代码,使您的答案更有帮助和实用。