将 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()
. 更容易
- 当您的数据位于简单数组而非关联数组中时,请使用位置参数占位符 (
?
) 而不是命名参数占位符。
我正在对数据进行一些清理和转换(该部分已完成,哇),并且需要将其插入 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()
. 更容易
- 当您的数据位于简单数组而非关联数组中时,请使用位置参数占位符 (
?
) 而不是命名参数占位符。