【问题标题】:Is there a shorthand for prepared statements?准备好的语句有简写吗?
【发布时间】:2020-11-17 03:17:12
【问题描述】:

最近我开始使用准备好的语句。但是,我觉得我的代码有点太混乱了,因为所有的临时变量和额外的行都需要进行单个查询。

到目前为止,我的代码如下所示:

$stmt = $conn->prepare("SELECT * FROM locations WHERE location_id = ?");
$stmt->bind_param("i", $_GET['location_id']);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($location_id, $owner);
//all the other $stmt->fetch() related code here...

是否有任何速记方法可以做同样的事情?

【问题讨论】:

  • 如果你使用bind_result,我认为你不需要store_result。但除此之外,四行代码到底是什么太长了?
  • 您可以使用过多的“包装器”*.. 即。 $result = $db->find('locations', 'location_id = ?', [$_GET['location_id']]) - 在 minemine woop 上有 10 次下载;p
  • 直接回答你的问题@PotatoGun,“不”。执行准备好的语句需要三个独特的操作……1)准备,2)绑定,3)执行。之后有几种检索结果的方法,所以这有点超出范围。如果这对您来说太冗长或重复,我们非常欢迎您将其封装成可重用的方法或使用第 3 方实现。
  • 当我开始做 PHP 工作时,我做的第一件事就是编写自己的 CRUD 对象,因为我无法忍受麻木的 $conn$stmt$q1 和 @987654332 @广告恶心。我也会推荐 PDO 而不是 mysqli。看看这个PDO wrapper
  • 这是一个很好的问题,被不公正地关闭和投票。当然是重复的,但这并没有使它变得不那么出色。只有极少数的 PHP 用户能够提出这个问题,他们更喜欢编写闪亮的重复运算符行列。 @Phil,虽然没有开箱即用的速记,但 programmer 可以 create 一个。而且,鉴于 mysqli 如此不合逻辑的混乱,请帮助创建它。

标签: php mysqli prepared-statement


【解决方案1】:

使用预处理语句是在 PHP 中执行 SQL 语句的正确方法,我必须真诚地赞扬你这样做的正确方法。

但是,您已经注意到 API 不适合在应用程序代码中使用准系统。大多数现代 PHP 应用程序都使用 PDO,即便如此,它也与某种抽象层一起使用。这些 API 并非旨在单独使用。

如果您必须使用 mysqli,那么您可以自己编写一个非常简单的包装类。包装器至少应该有两件事。一种使用默认参数打开连接的简单直观的方法,以及一种用于执行准备好的语句的简单单行方法。

考虑我的例子:

<?php

class DBClass extends mysqli {
    public function __construct($host, $user = null, $pass = null, $db = null, $port = null, $socket = null) {
        // enable error reporting
        mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
        // instantiate mysqli
        parent::__construct($host, $user, $pass, $db, $port, $socket);
        // set the correct charset
        $this->set_charset('utf8mb4');
    }

    /**
     * Executes prepared statement
     *
     * @param string $sql SQL query with placeholders e.g. SELECT * FROM users WHERE Id=?
     * @param array $params An array of parameters to be bound
     * @return array|null
     */
    public function safeQuery(string $sql, array $params = []): ?array {
        // prepare/bind/execute
        $stmt = $this->prepare($sql);
        if ($params) {
            $stmt->bind_param(str_repeat("s", count($params)), ...$params);
        }
        $stmt->execute();
        // If the query produces results then fetch them into multidimensional array
        if ($result = $stmt->get_result()) {
            return $result->fetch_all(MYSQLI_BOTH);
        }
        // return nothing if the query was successfully executed and it didn't produce results
        return null;
    }

    public function row(string $sql, array $params = []): ?array {
        return $this->safeQuery($sql, $params)[0] ?? [];
    }

    public function single(string $sql, array $params = []) {
        $data = $this->row($sql, $params);
        return array_shift($data);
    }
}

这是一个简单的类,它扩展了 mysqli 并向其添加了 3 个新方法:safeQueryrowsingle。您可以使用它们来执行静态查询或准备好的语句,并分别检索多行、单行或单个值。

以下是如何使用此类而不是 mysqli:

$db = new DBClass('localhost', 'user', 'pass', 'dbname');

// select multiple rows
$id = 2;
foreach ($db->safeQuery('SELECT title FROM movie WHERE directorId=?', [$id]) as $row) {
    echo $row['title']."\n";
}

// select a single row
$movie = $db->row('SELECT id FROM movie WHERE title=?', ['Titanic']);
if ($movie) {
    echo $movie['id']."\n";
}

// select a single column from a single row
echo $db->single('SELECT title FROM movie WHERE id=1');

值得指出的是store_result()bind_result() 方法不是非常有用,使用它们可能会导致脏代码。如果您使用与此处演示的一样简单的抽象类,则可以省去绑定变量并一一获取它们的麻烦。

【讨论】:

  • 看起来不错。很高兴有现场代码而不是一堆链接。
  • @Dharman 这个以及其他资源正是我想要的。为准备好的语句编写更清晰、更易读的代码的好方法。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多