准备好的语句有 shorthand 吗?
Is there a shorthand for prepared statements?
最近我开始使用准备好的语句。但是,我觉得我的代码变得有点太混乱了,因为所有的临时变量和额外的行只需要进行一次查询。
到目前为止,我的代码如下所示:
$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...
是否有任何shorthand方法可以做同样的事情?
使用prepared statements是在PHP中执行SQL语句的正确方法,我不得不由衷地赞扬你的正确做法
但是,正如您所注意到的,API 不适合在应用程序代码中使用准系统。大多数现代 PHP 应用程序都使用 PDO,即便如此,它也与某种抽象层一起使用。这些 API 并非设计为单独使用。
如果您必须使用 mysqli,那么您可以自己编写一个非常简单的包装器 class。包装器至少应该有两件事。一种使用默认参数打开连接的简单直观的方法和一种用于执行准备好的语句的简单单行方法。
考虑我的例子:
<?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);
}
}
这是一个简单的 class,它扩展了 mysqli 并向其添加了 3 个新方法:safeQuery
、row
和 single
。您可以使用它们来执行静态查询或准备好的语句,并分别检索多行、单行或单个值。
下面是如何使用 class 而不是 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()
方法并不是非常有用,使用它们会导致代码变脏。如果您使用抽象 class,即使像此处演示的那样简单,您也可以省去绑定变量并一一获取它们的麻烦。
最近我开始使用准备好的语句。但是,我觉得我的代码变得有点太混乱了,因为所有的临时变量和额外的行只需要进行一次查询。
到目前为止,我的代码如下所示:
$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...
是否有任何shorthand方法可以做同样的事情?
使用prepared statements是在PHP中执行SQL语句的正确方法,我不得不由衷地赞扬你的正确做法
但是,正如您所注意到的,API 不适合在应用程序代码中使用准系统。大多数现代 PHP 应用程序都使用 PDO,即便如此,它也与某种抽象层一起使用。这些 API 并非设计为单独使用。
如果您必须使用 mysqli,那么您可以自己编写一个非常简单的包装器 class。包装器至少应该有两件事。一种使用默认参数打开连接的简单直观的方法和一种用于执行准备好的语句的简单单行方法。
考虑我的例子:
<?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);
}
}
这是一个简单的 class,它扩展了 mysqli 并向其添加了 3 个新方法:safeQuery
、row
和 single
。您可以使用它们来执行静态查询或准备好的语句,并分别检索多行、单行或单个值。
下面是如何使用 class 而不是 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()
方法并不是非常有用,使用它们会导致代码变脏。如果您使用抽象 class,即使像此处演示的那样简单,您也可以省去绑定变量并一一获取它们的麻烦。