0

我正在尝试编写一个 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 变量可能是多行的。

4

0 回答 0