php - 自定义 mysqli 准备函数

标签 php class mysqli prepared-statement bindparam

我现在正在做我的第一个自己的数据库类,目前我正在做准备功能。

该函数的作用是接收 SQL 查询,然后接收包含语句变量的数组。我在将参数绑定(bind)到语句时遇到问题。

这就是函数现在的样子

public function prepare($query, $var) {
    $types = '';
    foreach($var as $a) {
        $type = gettype($a);
        switch($type) {
            case 'integer':
                $types .= 'i';
                break;

            case 'string':
                $types .= 's';
                break;

            default:
                exit('Invalid type: ' . $a .' ' . $type . '(' . count($a) . ')');
                break;
        }
    }

    $stmt = self::$connection->prepare($query);
    $stmt->bind_param($types, $var); // How do I do here??
    $stmt->execute();
    $result = $stmt->get_result();
    while($row = $result->fetch_assoc()) {
        print_r($row);
    }
}

一切都按照我想要的方式工作(我知道这个函数可以做一些改进,但它做了它需要做的事情)。我已经评论了我无法弄清楚该怎么做的那一行。 $var 是一个数组,如果我没记错的话,变量需要用逗号分隔单独传递。这就是我无知的地方。

最佳答案

您自己的数据库类的想法非常棒。
这里很少有人分享它,出于某种原因,他们更喜欢原始 api 调用而不是他们的代码。
所以,您又向前迈出了一大步。
然而,这里有一些反对意见:

  1. 如果您要使用 native 准备好的语句,请不要将 mysqli 用于您的第一个自己的数据库类。
    请改用 PDO。这将为您省去很多麻烦。
  2. 尽管这个函数对你来说没问题,但它没有多大意义:
    • switch($type) 代码块没有用。 Mysql 可以将每个标量值理解为字符串 - 因此您可以毫无问题地将每个值绑定(bind)为 s
    • 无论如何,大多数来自客户端的整数都是字符串类型。
    • 有一些合法类型,例如 floatNULL 或可以返回字符串的对象。所以,自动化在这里不起作用。如果您想区分不同的类型,则必须实现类型提示占位符
    • 切勿在脚本中使用exit改为抛出新的异常('将您的错误消息放在这里')
  3. 这实际上并不是一个准备函数,因为它也会执行。所以,给它一个更通用的名称

但是现在你的问题
这是使用 mysqli 的直接结果。处理准备好的语句时这是一场噩梦。不仅可以绑定(bind),还可以检索数据(因为 get_result() 并非在任何地方都能工作,在本地创建应用程序后,您会发现它无法在共享主机上工作)。您可以通过查看 this bunch of code 给自己一个想法。正是出于这个目的 - 绑定(bind)动态数量的变量。

所以,尽可能远离 mysqli。
使用 PDO,您的功能将像这样简单

public function query($query, $var=array())
{
    $stmt = self::$connection->prepare($query);
    $stmt->execute($var);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// and then used
$data = $db->("SELECT 1");
print_r($data);

您可以take a look at my class获得一些想法。
请随意询问有关数据库类的任何问题 - 这是很棒的事情,我很高兴您这样做。

回答评论中的问题。

让您知道,您并不是该网站的唯一用户。还有一些无辜的游客。与您不同,他们不需要错误消息,并且他们会因为一些奇怪的行为和缺乏熟悉的控制而感到害怕。

带有错误消息的 exit() 做了很多邪恶的事情

  • 抛出错误消息,向潜在攻击者泄露一些系统内部信息
  • 用奇怪的消息吓唬无辜的用户。 “那是什么?谁无效?是我的错还是什么?或者可能是病毒?最好离开该网站”- 他们想。
  • 在中间删除脚本,因此可能会导致显示设计撕裂(或根本没有设计)
  • 不可恢复地终止脚本。而抛出的异常可以被捕获并妥善处理

连接到 PDO 时,无需在此处抛出任何内容,因为 PDO 已抛出异常。因此,摆脱 try ... catch 并只保留一行:

self::$connection = new PDO($dsn, $user, $pass); 

然后创建一个自定义exception handler以两种模式工作:

  • 在开发服务器上让它将消息扔到屏幕上。
  • 在实时服务器上,让它记录错误,同时向用户显示通用错误页面

仅当您不想整个脚本死亡时才使用 try ... catch - 即仅处理可恢复问题。

顺便说一句,PDO 默认情况下不会在连接时抛出异常。您必须手动设置它:

$opt = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION );
self::$connection = new PDO($dsn, $user, $pass, $opt); 

关于php - 自定义 mysqli 准备函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14970407/

相关文章:

php - 这个 HTML 右括号从哪里来?

c++ - 如何实例化类的公共(public)成员并将其作为 std::promise 返回?

php - 连接查询中的脚本查询问题

PHP 7 session_regenerate_id 失败和 PDO 调用成员函数prepare() null

php - 无密码 mysql_connect

php - 桌面应用程序如何从网站获取信息?

java - 重构代码以尊重 OOP 原则

PHP 未将提交的数据上传到数据库

javascript - 使用 jQuery 和正确的按钮 ID 将正确的内容应用到模式中

c++ - 定义 operator<< 内部类