我正忙于从数据库获取设置的函数,突然间,我遇到了这个错误:
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'
)
现在奇怪的是;表存在,请求的设置存在,数据库存在,但仍然,该错误不会离开。以下是DB正确的证据:
答案 0 :(得分:107)
问题在于:
$query = $this->db->conn->prepare('SELECT value, param FROM ws_settings WHERE name = ?');
$query->bind_param('s', $setting);
prepare()
方法可以返回false
,您应该检查一下。至于它返回false
的原因,表名或列名(在SELECT
或WHERE
子句中)可能不正确吗?
另外,请考虑使用类似$this->db->conn->error_list
的内容来检查解析SQL时发生的错误。 (我偶尔会回复实际的SQL语句字符串并粘贴到phpMyAdmin进行测试,但肯定会出现问题。)
答案 1 :(得分:18)
任何时候你得到......
"致命错误:在布尔值"
上调用成员函数bind_param()
...可能是因为您的查询存在问题。 prepare()
可能会返回FALSE
(布尔值),但这个通用的失败消息并没有给您留下太多线索。你怎么知道你的查询有什么问题?你问!
首先,确保错误报告已打开且可见:在打开<?php
标记后立即将这两行添加到文件顶部:
error_reporting(E_ALL);
ini_set('display_errors', 1);
如果您在php.ini中设置了错误报告,则您不必担心这一点。只需确保您优雅地处理错误,并且永远不会向用户透露任何问题的真正原因。向公众展示真正的事业可以为那些想要伤害您的网站和服务器的人提供金色邀请函。如果您不想将错误发送到浏览器,则可以始终监视Web服务器错误日志。日志位置因服务器而异,例如,在Ubuntu上,错误日志通常位于/var/log/apache2/error.log
。如果您正在检查Linux环境中的错误日志,则可以在控制台窗口中使用tail -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
列,解决问题是微不足道的。
如果您选择,您可以在函数或类中包含此检查,并通过如前所述优雅地处理错误来扩展它。
答案 2 :(得分:11)
prepare
仅在FALSE
失败时才返回布尔值,以避免在执行前首先检查True
是否需要错误:
$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);
}
答案 3 :(得分:10)
即使查询语法正确,准备也可能返回false,如果有前一个语句但它没有关闭。 始终使用
关闭之前的声明$statement->close();
如果语法正确,以下查询也会运行良好。
答案 4 :(得分:1)
可能导致此问题的另一种情况是查询中的错误转换。
我知道这听起来很明显,但我使用tablename
代替Tablename
遇到了这种情况。检查您的查询,并确保您使用与表格中列的实际名称相同的大小写。
答案 5 :(得分:0)
有时,这也是因为准备声明 中的错误的表格名称或列名称 。
请参阅this。
答案 6 :(得分:0)
你应该尽可能多地尝试将你的陈述总是放在try catch块中......在这种情况下它会一直有用,会让你知道什么是错的。表名或列名可能是错误的。
答案 7 :(得分:0)
此特定错误与实际错误几乎没有关系。这是我的类似经历和解决方案......
我在我的声明中使用了一个表|database-name|.login
复合名称。我认为这不是问题。这确实是问题所在。将它括在方括号内解决了我的问题([|database-name|].[login]
)。所以,问题是MySQL保留的单词(换句话说)...确保你的列也没有失败到这种类型的错误场景......
答案 8 :(得分:0)
有时显式声明表列名称(尤其是在插入查询中)可能有所帮助。例如,查询:
INSERT INTO tableName(param1, param2, param3) VALUES(?, ?, ?)
可能会更好,而不是:
INSERT INTO tableName VALUES(?, ?, ?)
答案 9 :(得分:0)
我注意到该错误是由于我将表字段名称作为变量传递而引起的,即我发送了:
$stmt = $this->con->prepare("INSERT INTO tester ($test1, $test2) VALUES (?, ?)");
代替:
$stmt = $this->con->prepare("INSERT INTO tester (test1, test2) VALUES (?, ?)");
请注意,表字段名在字段名之前包含$
。他们不应在那里,$field1
应该是field1
。
答案 10 :(得分:0)
以我的经验,bind_param
很好,但是我误认为了数据库名称,因此,我仅更改了连接参数中的数据库名称,并且效果很好。
我已经定义了根路径来指示根文件夹,包括路径以包括文件夹和网站的主页URL的基本URL。这将用于在需要它们的任何地方调用它们。
答案 11 :(得分:-1)
以下两个是导致此问题的最可能原因:
$stmt->close(); // <<<-----This fixed the issue for me
$stmt = $conn->prepare("Insert statement");