我正在尝试编写一个 PHP 函数,它可以(给定一个带有命名 printf 样式参数的 SQL 查询和一个关联数组)用问号(对于 SQL 准备语句)替换命名参数并重新排列数组,以便参数是按照它们在查询中出现的顺序。
我编写了以下代码,它可以工作,但是我想扩展此代码以忽略出现在注释中的命名参数。
function sqlprintfn($sql, array $args = array()) {
$ordered_args = array();
static $formats = array('b','c','d','e','E','u','f','F','g','G','o','s','x','X');
$regex = sprintf('/(\?\(([a-zA-Z_]\w*)\)([%s]))/', implode('', $formats));
// Find the next named argument. Each search starts at the end of the previous replacement
for ($pos = 0; preg_match($regex, $sql, $match, PREG_OFFSET_CAPTURE, $pos);) {
$arg_pos = $match[0][1];
$arg_len = strlen($match[0][0]);
$arg_key = $match[2][0];
$arg_format = $match[3][0];
// Programmer did not supply a value for the named argument found in the format string
if (!array_key_exists($arg_key, $args)) {
trigger_error(sprintf('%s(): Missing argument \'%s\'', __FUNCTION__, $arg_key), E_USER_WARNING);
return false;
}
array_push($ordered_args, $args[$arg_key]);
// Replace the named argument with a question mark
$sql = substr_replace($sql, $replace = '?', $arg_pos, $arg_len);
$pos = $arg_pos + strlen($replace); // skip to end of replacement for next iteration
}
return array_merge((array) $sql, $ordered_args);
}
作为我想要实现的一个例子:
$sql = 'SELECT id FROM users WHERE username = ?(username)s AND type = ?(type)s';
$params = array('type' => 'admin', 'username' => 'bob', email => 'bob@domain.com');
print_r(sqlprintfn($sql, $params));
应该输出:
Array
(
[0] => 'SELECT id FROM users WHERE username = ? AND type = ?',
[1] => 'bob',
[2] => 'admin'
)
和:
$sql = 'SELECT id FROM users WHERE /* email = ?(email)s AND */ username = ?(username)s AND type = ?(type)s';
$params = array('type' => 'admin', 'username' => 'bob', email => 'bob@domain.com');
print_r(sqlprintfn($sql, $params));
应该输出:
Array
(
[0] => 'SELECT id FROM users WHERE /* email = ?(email)s AND */ username = ? AND type = ?',
[1] => 'bob',
[2] => 'admin'
)
另外,请注意 $sql 变量可能是多行的。