在 PHP PDO 中,如何在不知道名称的情况下绑定准备好的语句的命名参数?
In PHP PDO, how can I bind named parameters of a prepared statement without knowing their names?
我正在尝试编写一个辅助查询函数来 return 调用者的结果集,但是当调用者使用命名参数提供准备好的语句时,我不确定如何将它们绑定到函数中。
function queryDB(string $query, array $param=null) {
global $dbh; //reference the db handle declared in init.php
if (isset($param)) { //query params provided, so a prepared statement
$stmt = $dbh->prepare($query);
for($i = 1; $i <= count($param);$i++) { //bind the parameters 1-by-1
$stmt->bindParam($i, $param[$i]); //
}
$stmt->execute();
} else { //a straight sql query, not a prepared statement
$stmt = $dbh->query($query);
}
$result = $stmt->fetchAll();
return $result;
}
如果我使用 $query = INSERT INTO users (name, age) VALUES(?, ?)
和 $name = "trump"; $age = 18
等未命名参数准备语句调用 queryDB($query, [$name, $age])
,该代码应该有效。
但有时我(或其他人)会使用命名参数准备语句进行调用,例如 $query = INSERT INTO users (name, age) VALUES(:name, :age)
和 $name = "trump"; $age = 18
。现有的 bindParam(i, $value) 不应该工作,但是函数不知道那些 :name, :age, :whatever
命名参数。我应该如何编写 bindParam(param, value)
以适应命名和未命名的准备语句?假设参数将以匹配的顺序提供,即使在命名时也是如此。
函数更新 关注@Dharman
的评论
/*
Helper function to query database and return the full resultset.
@param $query: the SQL query string, can be either a straight query (without any external inputs) or a prepared statement using either named parameters (:param) or positional (?)
@param $param: the values, in array, to bind to a prepared statement, [value1, value2, ...] or ["name1" => value1, "name2" => value2, ...] for positional or named params
@return full resultset of the query
*/
function queryDB(string $query, array $param=null) {
global $dbh; //reference the db handle declared in init.php
if (isset($param)) { //query params provided, so a prepared statement
$stmt = $dbh->prepare($query); //set up the prepared statement
$isAssocArray = count(array_filter(array_keys($param), "is_string")) == 0 ? false : true; //boolean flag for associative array (dict, with keys) versus sequential array (list, without keys)
if ($isAssocArray) { //the prepared statement uses named parameters (:name1, :name2, ...)
foreach($param as $name => $value) { //bind the parameters 1-by-1
if (substr($name, 0, 1) != ":") { //if the provided parameter isn't prefixed with ':' which is required in bindParam()
$name = ":".$name; //prefix it with ':'
}
$stmt->bindParam($name, $value);
}
} else { //the prepared statement uses unnamed parameters (?, ?, ...)
for($i = 1; $i <= count($param); $i++) { //bind the parameters 1-by-1
$stmt->bindParam($i, $param[$i]);
}
} //the prepared statement has its values bound and ready for execution
$stmt->execute();
} else { //not a prepared statement, a straight query
$stmt = $dbh->query($query);
}
$resultset = $stmt->fetchAll();
return $resultset;
}
绝对没有理由使用 bindParam
。
如果您的 SQL 有命名占位符,那么您的数组必须是关联的。你需要这样称呼它:
queryDB($query, ['name' => $name, 'age' => $age]);
然后您可以使用 foreach($params as $key => $value)
循环并使用 bindParam
但正如我所说,绝对没有理由使用它。
而是将数组传递给 execute
。
function queryDB(PDO $dbh, string $query, ?array $param = null)
{
$stmt = $dbh->prepare($query);
$stmt->execute($param);
return $stmt->fetchAll();
}
P.S。您甚至可以删除 if
语句和对 query
的调用。此方法与 prepare
和 execute
的作用相同。没有理由在您的代码中有这样的特殊情况。
我正在尝试编写一个辅助查询函数来 return 调用者的结果集,但是当调用者使用命名参数提供准备好的语句时,我不确定如何将它们绑定到函数中。
function queryDB(string $query, array $param=null) {
global $dbh; //reference the db handle declared in init.php
if (isset($param)) { //query params provided, so a prepared statement
$stmt = $dbh->prepare($query);
for($i = 1; $i <= count($param);$i++) { //bind the parameters 1-by-1
$stmt->bindParam($i, $param[$i]); //
}
$stmt->execute();
} else { //a straight sql query, not a prepared statement
$stmt = $dbh->query($query);
}
$result = $stmt->fetchAll();
return $result;
}
如果我使用 $query = INSERT INTO users (name, age) VALUES(?, ?)
和 $name = "trump"; $age = 18
等未命名参数准备语句调用 queryDB($query, [$name, $age])
,该代码应该有效。
但有时我(或其他人)会使用命名参数准备语句进行调用,例如 $query = INSERT INTO users (name, age) VALUES(:name, :age)
和 $name = "trump"; $age = 18
。现有的 bindParam(i, $value) 不应该工作,但是函数不知道那些 :name, :age, :whatever
命名参数。我应该如何编写 bindParam(param, value)
以适应命名和未命名的准备语句?假设参数将以匹配的顺序提供,即使在命名时也是如此。
函数更新 关注@Dharman
的评论
/*
Helper function to query database and return the full resultset.
@param $query: the SQL query string, can be either a straight query (without any external inputs) or a prepared statement using either named parameters (:param) or positional (?)
@param $param: the values, in array, to bind to a prepared statement, [value1, value2, ...] or ["name1" => value1, "name2" => value2, ...] for positional or named params
@return full resultset of the query
*/
function queryDB(string $query, array $param=null) {
global $dbh; //reference the db handle declared in init.php
if (isset($param)) { //query params provided, so a prepared statement
$stmt = $dbh->prepare($query); //set up the prepared statement
$isAssocArray = count(array_filter(array_keys($param), "is_string")) == 0 ? false : true; //boolean flag for associative array (dict, with keys) versus sequential array (list, without keys)
if ($isAssocArray) { //the prepared statement uses named parameters (:name1, :name2, ...)
foreach($param as $name => $value) { //bind the parameters 1-by-1
if (substr($name, 0, 1) != ":") { //if the provided parameter isn't prefixed with ':' which is required in bindParam()
$name = ":".$name; //prefix it with ':'
}
$stmt->bindParam($name, $value);
}
} else { //the prepared statement uses unnamed parameters (?, ?, ...)
for($i = 1; $i <= count($param); $i++) { //bind the parameters 1-by-1
$stmt->bindParam($i, $param[$i]);
}
} //the prepared statement has its values bound and ready for execution
$stmt->execute();
} else { //not a prepared statement, a straight query
$stmt = $dbh->query($query);
}
$resultset = $stmt->fetchAll();
return $resultset;
}
绝对没有理由使用 bindParam
。
如果您的 SQL 有命名占位符,那么您的数组必须是关联的。你需要这样称呼它:
queryDB($query, ['name' => $name, 'age' => $age]);
然后您可以使用 foreach($params as $key => $value)
循环并使用 bindParam
但正如我所说,绝对没有理由使用它。
而是将数组传递给 execute
。
function queryDB(PDO $dbh, string $query, ?array $param = null)
{
$stmt = $dbh->prepare($query);
$stmt->execute($param);
return $stmt->fetchAll();
}
P.S。您甚至可以删除 if
语句和对 query
的调用。此方法与 prepare
和 execute
的作用相同。没有理由在您的代码中有这样的特殊情况。