微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 PHP 中的准备语句中将命名参数转换为未命名

如何解决在 PHP 中的准备语句中将命名参数转换为未命名

我有一个使用命名占位符的 sql 查询,以及一个包含相应键和值的关联数组。

INSERT INTO table1 (a,b,c) VALUES (:a,:b,:c)
[
  'a' => 'ValueA','c' => 'ValueC','b' => 'ValueB'
]

现在我需要将查询 - 以及相应的参数 - 转换为使用未命名(问号)。

INSERT INTO table1 (a,c) VALUES (?,?,?)
[
  0 => 'ValueA',1 => 'ValueB',2 => 'ValueC'
]

我怎样才能做到这一点,而不会冒着参数以错误顺序结束的风险?

解决方法

我会使用 preg_replace_callback 并简单地将相应参数的值附加到新数组中:

/**
 * @return mixed[] An array containing two elements: the modified SQL query (string),*                 and the modified params (array).
 */
function unnameSqlParameters(string $sql,array $params): array
{
    $newParams = [];

    $newSql = preg_replace_callback(
        '/:(\w+)/',static function (array $matches) use ($params,&$newParams): string {
            $name = $matches[1];

            if (!array_key_exists($name,$params)) {
                throw new \RuntimeException("Cannot find parameter value for :{$name}.");
            }

            $newParams[] = $params[$name];

            return '?';
        },$sql
    );

    return [$newSql,$newParams];
}

用法:

[$sql,$params] = unnameSqlParameters(
    'INSERT INTO table1 (a,b,c) VALUES (:a,:b,:c)',['a' => 'ValueA','c' => 'ValueC','b' => 'ValueB']
);

Demo

请注意,所使用的正则表达式也将匹配字符串中的参数(例如 :a)。如果需要,有一些方法可以防止这种情况发生。

,

我想出了以下函数,其中考虑到

  • 部分匹配的占位符名称,即 :b:bar
  • 参数在 SQL 和参数数组中以不同的顺序出现
function sqlNamedPlaceholdersToUnnamed(string &$sql,array &$params){
    // Sort params based on the order their keys appear in $sql
    $newParams = [];
    foreach($params as $key => $value){
        $result = preg_match("/:{$key}[^a-zA-Z0-9_]/",$sql,$matches,PREG_OFFSET_CAPTURE);

        if( $result !== 1 ) throw new \Exception("Unexpected result from preg_match. Expected 1,but got $result");
        $newParams[(int) $matches[0][1]] = $value;
    }
    ksort($newParams,SORT_NUMERIC);
    $newParams = array_values($newParams);


    // Replace named parameters with ? in $sql
    $newSql = preg_replace("/:[a-zA-Z0-9_]+/",'?',-1,$count);
    if( $newSql === null ) throw new \Exception('Error when executing preg_replace');
    if( $count !== count($params) ) throw new \Exception("Number of placeholders not same as number of params");


    // Replace arguments with results
    $sql = $newSql;
    $params = $newParams;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。