【问题标题】:Custom mysqli prepare function自定义 mysqli 准备函数
【发布时间】:2013-02-04 21:31:24
【问题描述】:

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

这个函数的作用是接受一个 SQL 查询,然后是一个包含语句变量的数组。我在将参数绑定到语句时遇到问题。

这就是函数现在的样子

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 是一个数组,如果我没记错的话,变量需要用逗号分开传递。这就是我无能为力的地方。

【问题讨论】:

  • 提示:您设置的通用标签越多,您的问题就越受到关注。它当时只有 7 个视图,这都归功于您选择的复杂标记。 php 总是一个不错的选择。

标签: php class mysqli prepared-statement bindparam


【解决方案1】:

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

  1. 如果您要使用本机准备好的语句,请不要将 mysqli 用于您自己的第一个数据库类。
    请改用 PDO。它将为您省去很多麻烦。
  2. 尽管这个函数对你来说很好用,但它没有多大意义:
    • switch($type) 代码块没用。 Mysql 可以将每个标量值理解为字符串 - 因此您可以将每个值绑定为 s 没有问题。
    • 大多数来自客户端的整数都具有字符串类型。
    • 有一些合法的类型,如floatNULL 或可以返回字符串的对象。所以,自动化在这里行不通。如果你想区分不同的类型,你必须实现类型提示的占位符
    • 切勿在您的脚本中使用exitthrow new Exception('put here your error message') 代替。
  3. 这实际上不是一个准备函数,因为它也执行。所以,给它更通用的名字

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

所以,请尽可能远离 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获得一些想法。
随意询问有关数据库类的任何问题 - 这是一件很棒的事情,我很高兴你能走这条路。

回答 cmets 的问题。

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

带有错误信息的exit()会做很多坏事

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

当连接到 PDO 时,不需要在这里抛出任何东西,因为 PDO已经抛出了异常。所以,去掉try ... catch,只留下一行:

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

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

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

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

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

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

【讨论】:

  • 我知道 PDO 比 Mysqli 好得多,但我一直懒得切换到 PDO,我想我现在就开始吧!为什么我不应该使用 exit()?抛出异常和使用 exit() 有什么区别?这怎么样?我也应该在这里抛出异常吗?尝试 { self::$connection = new PDO($dsn, $user, $pass); } catch (PDOException $e) { exit('连接失败:' . $e->getMessage(); }
猜你喜欢
  • 2016-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-12
  • 2010-11-17
相关资源
最近更新 更多