Is there a shorthand for prepared statements?

扶醉桌前 提交于 2021-01-20 07:14:40

问题


Recently I've started to use prepared statements. However, I feel like my code becomes a bit too cluttered with all the temporary variables and extra lines required just to make a single query.

So far my code looks like the following:

$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...

Are there any shorthand methods to do the same thing?


回答1:


Using prepared statements is the correct way to execute SQL statements in PHP, and I have to sincerely commend you for doing it the right way.

However, as you have noticed the API is not suitable to be used barebone in an application code. Most modern PHP applications use PDO and even then it's used with some kind of abstraction layer. These APIs were not designed to be used on their own.

If you must use mysqli then you can write a very simple wrapper class yourself. The wrapper should at least have two things. An easy and intuitive way of opening the connection with default parameters and a simple one-liner method for executing prepared statements.

Consider my example:

<?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);
    }
}

This is a simple class that extends mysqli and adds 3 new methods to it: safeQuery, row and single. You can use them to execute a static query or a prepared statement and retrieve multiple rows, a single row, or a single value respectively.

Here is how one would use such class instead of 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');

Worth pointing out is that the store_result() and bind_result() methods are not extremely useful and using them can lead to a dirty code. If you use an abstraction class even as simple as the one demonstrated here you can save yourself the trouble of binding the variables and fetching them one by one.



来源:https://stackoverflow.com/questions/64868834/is-there-a-shorthand-for-prepared-statements

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!