将 PHP 关联数组映射到 PDO 准备语句

Mapping PHP associative arrays into PDO prepared statements

我正在对数据进行一些清理和转换(该部分已完成,哇),并且需要将其插入 MySQL table。之前在 Perl 中做过这种事情,我认为,作为处理的一部分,我将数据结构化为一个关联数组,键与我需要将它们加载到的字段名称相同 -这样,只需遍历键并生成一个包含命名占位符和匹配值的列表,就可以很容易地构造一个准备好的语句。

但是,我似乎无法在 PHP/PDO 中完成这项工作。测试代码:

$x = <<<EOD
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
EOD;

$fields = array('name', 'job', 'wallet_size', 'inseam', 'pet_name');
foreach(explode("\n", $x) as $line){
    $data = array_combine($fields, explode(' ', $line));

    # print_r($data);

    $stmt = $dbh->prepare('INSERT INTO foobar VALUES('.':'.implode(', :', $fields));

    foreach($fields as $field){
        $stmt->bindParam(':'.$field, $data[$field]);
    }
    $stmt->execute();
}

坦率地说,工作起来感觉太……粗鲁和笨拙——事实并非如此。

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1' in tst.php:24

一个正确的方法,对吧?如果有人能向我介绍适当的 PHP 风格的措辞,我将不胜感激。

当您盯着格式化 SQL 的 PHP 代码而不是最终的 SQL 字符串本身时,很难调试 SQL。我建议你总是创建一个字符串变量,这样你就可以在调试期间输出它。

$sql = 'INSERT INTO foobar VALUES('.':'.implode(', :', $fields);
echo "$sql\n";
$stmt = $dbh->prepare($sql);

输出:

INSERT INTO foobar VALUES(:name, :job, :wallet_size, :inseam, :pet_name

现在很容易看出您忘记了在该 INSERT 语句末尾结束 )

此外,您对 PDO 的使用比需要的更困难。您不需要使用命名参数。您不需要使用 bindParam()。下面是我将如何编写这段代码:

$fields = array('name', 'job', 'wallet_size', 'inseam', 'pet_name');

$columns = implode(',', $fields);
$placeholders = implode(',', array_fill(1, count($fields), '?'));
$sql = "INSERT INTO foobar ($columns) VALUES ($placeholders)";
echo "$sql\n"; // use this during debugging
$stmt = $dbh->prepare($sql);

foreach(explode("\n", $x) as $line){
    $param_values = explode(' ', $line);
    $stmt->execute($param_values);
}

提示:

  • 准备一次查询,然后为要插入的每一行数据重新使用准备好的语句。
  • 将一组数据值作为参数传递给 execute()。这比使用 bindParam().
  • 更容易
  • 当您的数据位于简单数组而非关联数组中时,请使用位置参数占位符 (?) 而不是命名参数占位符。