如何使用mysqli准备好的语句?

问题描述 投票:0回答:3

我正在尝试准备好的语句,但下面的代码不起作用。我收到错误:

致命错误:在非对象上调用成员函数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 来准备语句吗?谁能给我提供一个完整的示例,说明从连接到插入到选择以及错误处理的准备语句?

php mysql mysqli prepared-statement
3个回答
11
投票

来自

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

7
投票

我还需要使用 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));

4
投票

连接

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
中。

© www.soinside.com 2019 - 2024. All rights reserved.