我正在尝试准备好的语句,但下面的代码不起作用。我收到错误:
致命错误:在非对象上调用成员函数execute() /var/www/prepared.php 第 12 行
<?php
$mysqli = new mysqli("localhost", "root", "root", "test");
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: " . $mysqli->connect_error;
}
$stmt = $mysqli->prepare("INSERT INTO users (name, age) VALUES (?,?)");
// insert one row
$stmt->execute(array('one',1));
// insert another row with different values
$stmt->execute(array('two',1));
?>
另外,我需要使用 mysqli 来准备语句吗?谁能给我提供一个完整的示例,说明从连接到插入到选择以及错误处理的准备语句?
mysqli::prepare
文档:
在执行语句或获取行之前,必须使用 mysqli_stmt_bind_param() 和/或 mysqli_stmt_bind_result() 将参数标记绑定到应用程序变量。
bind_param
文档。
即:
$name = 'one';
$age = 1;
$stmt = $mysqli->prepare("INSERT INTO users (name, age) VALUES (?,?)");
// bind parameters. I'm guessing 'string' & 'integer', but read documentation.
$stmt->bind_param('si', $name, $age);
// *now* we can execute
$stmt->execute();
我还需要使用 mysqli 来准备语句吗?任何人都可以向我指出一个关于准备好的语句的完整示例,从连接到插入到选择以及错误处理
您还可以使用我更喜欢的 PDO。事实上,看起来您在代码示例中混淆了 PDO 和 Mysqli。
$db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("INSERT INTO users (name, age) VALUES (?,?)");
$stmt->execute(array($name1, $age1));
$stmt->execute(array($name2, $age2));
与 mysqli 不同,您不必调用单独的绑定函数,尽管如果您喜欢/想要/需要使用该功能,则可以使用它。
PDO 的另一个有趣的事情是命名占位符,它在复杂查询中可以减少混乱:
$db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("INSERT INTO users (name, age) VALUES (:name,:age)");
$stmt->execute(array(':name' => $name1, ':age' => $age1));
$stmt->execute(array(':name' => $name2, ':age' => $age2));
mysqli 连接的重要性经常被忽视,被简化为一行。而正确的连接代码可以解决从安全性到可用性的许多问题。
鉴于您的代码是通常的程序 PHP,这里是一个要包含在脚本中的简单 mysqli 连接代码:
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli($host, $user, $pass, $db);
$mysqli->set_charset($charset);
unset($host, $db, $user, $pass, $charset); // we don't need them anymore
完整的解释可以在我的文章如何使用 mysqli 正确连接(以及许多有用的提示)中找到,但只是一个小引用来突出显示最重要的部分:
- 为连接设置正确的字符集将消除整类错误,例如奇怪的字符/问号而不是数据、空的 json_encode() 输出、存储表情符号的问题等。
- 设置正确的错误报告模式将消除神秘的错误消息,例如 mysqli_fetch_assoc()需要参数.../调用成员函数bind_param()...,而是为您提供来自MySQL的实际错误消息。
插入查询比较简单,其他答案中已经介绍过。
您所需要做的就是用问号替换查询中的所有变量(以及周围的引号!),然后准备查询,然后将所有变量及其类型推入
bind_param()
,最后执行查询。
只有一个快速提示:MySQL 很乐意接受所有变量作为字符串,所以不要疯狂地寻找某个变量的正确类型,只需使用“s”来表示任何变量。
所以基本上插入就是这样的
$sql = "INSERT INTO users (name, email, password) VALUES (?,?,?)";
$stmt= $conn->prepare($sql);
$stmt->bind_param("sss", $name, $email, $password_hash);
$stmt->execute();
同样的原则应该适用于所有其他查询类型,例如 UPDATE 或 DELETE。
运行 select 查询 几乎相同,但有一个小技巧。由于某些未知的原因,您无法立即在准备好的语句中使用熟悉的获取函数。所以你需要先获取 mysqli_result,然后你才能使用
fetch_assoc()
、fetch_obj()
等:
$sql = "SELECT * FROM users WHERE id=?"; // SQL with parameters
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$user = $result->fetch_assoc(); // fetch data
提示:完全不需要熟悉的
mysqli_num_rows()
功能。如果您想到这一点,您始终可以使用数据本身来查看查询是否返回任何行:
$user = $result->fetch_assoc();
if ($user) {
// found!
}
多行也是如此,感谢
另一个提示:有一个方便的函数
fetch_all()
,可以一次性获得所有选定行的数组。例如,如果查询返回多行,您可以通过将最后一行更改为将它们放入数组中
$users = $result->fetch_all(MYSQLI_ASSOC); // fetch data
错误处理是最重要但又有些令人惊讶的部分。尽管有大量文章和示例所说,但作为一项规则,您根本不应该编写任何错误处理代码。这听起来绝对是疯狂的,但这正是事情必须要做的。大多数时候,您所需要做的只是报告错误。 mysqli/PHP 已经可以为您做到这一点,无需任何帮助。因此,您不应该编写任何验证查询执行结果的代码 - 如果出现错误,mysqli 将自动报告错误,这要归功于 #Connection 部分中提到的
mysqli_report()
函数调用。同样,这个原理的完整解释可以在另一篇文章中找到,专门讨论一般的PHP错误报告。
在极少数情况下,当您确实需要处理错误时,即在出现错误时执行一些操作,而不是仅仅报告错误,然后将您的查询包装在
try..catch
中。