1

我愚蠢地用 mysqli 构建了我的 Web 应用程序。现在,我正在尝试将我的数据抽象层转换为 pdo,但由于某种原因,插入查询给我带来了麻烦。我的快捷插入函数是从控制器调用的,我希望将其保持为名称格式,并以表名和列/值数组作为参数。

我评论了我认为问题出在哪里。请帮忙。

function insert($table, array $columns_values) {        

    // connect to db
    $dbh = $this->db_connect();

    $i = 0;

    $columns = array();
    $values  = array();
    $params  = array();

    foreach($columns_values as $column => $value) {

        $i++;

        $param = array($i => $value);
        array_push($params, $param);

        array_push($columns, $column);
        array_push($values, '?');

    }

    // turn arrays into comma separated list
    $columns =      implode(",", $columns);
    $values  =      implode(",", $values);


    $stmt = $dbh->prepare("INSERT INTO $table ($columns) VALUES ($values)");


    foreach ($params as $param_stmt) {

             // i think this is where the problem is
            foreach ($param_stmt as $placeholder => $value) {

                $stmt->bindParam($placeholder, $value);

            }


    }

    $stmt->execute();

    return $stmt;

} // end insert()
4

3 回答 3

2

我不会按照你的方式去做。几分钟后,我想出了这个:

/**
 * Function to insert a list of values to the database.
 * 
 * @param PDO    $pdo
 * @param string $table
 * @param array  $columns_values
 *
 * @throws \Exception
 * @throws \PDOException
 */
function insert_to_db(PDO $pdo, $table, array $columns_values) {
    //Some data validation.
    if (empty($columns_values)) {
        throw new \Exception("Insert at least one value.");
    }
    if (empty($table)) {
        throw new \Exception("Table may not be empty.");
    }

    //Implode all of column names. Will become the columns part of the query.
    $str_columns = implode(", ", array_keys($columns_values));

    //Implode all column names after adding a : at the beginning.
    //They will become the placeholders on the values part.
    $prepared_column_names = array_map(function ($el) {
        return ":$el";
    }, array_keys($columns_values));
    $prepared_str_columns  = implode(", ", $prepared_column_names);

    //The query itself. Will look like "INSERT INTO `$table` (col1, col2, col3) VALUES (:col1, :col2, :col3);"
    $query = "INSERT INTO `$table` ($str_columns) VALUES ($prepared_str_columns);";

    //Prepare the query
    $stmt = $pdo->prepare($query);

    //Iterate over the columns and values, and bind the value to the placeholder
    foreach ($columns_values as $column => $value) {
        $stmt->bindValue(":$column", $value);
    }

    //Execute the query
    $stmt->execute();

}

我改变的东西

  1. 我没有在函数内部实例化 PDO 对象。该函数需要一个才能工作,所以它应该是参数之一!
  2. 如果出现错误,我会抛出Exception。这是处理错误的更好方法。
  3. 我使用命名占位符而不是未命名的占位符(:namevs ?)。如果您需要调试,则生成更具可读性、更易于跟踪的查询。
  4. 在代码中添加了注释。再说一次,你现在明白你写了什么,但你会在 6 个月后吗?
  5. 我利用array_keys()自动生成一个充满键的数组(即列),而不是循环并手动添加一个。

一些技巧

  • 当你实例化一个 PDO 对象时,确保它抛出PDOExceptions 错误!像这样:

    new PDO($dsn, $user, $pass, array(PDO::PARAM_ERRMODE => PDO::ERRMODE_EXCEPTION));
    

    或者

    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::PARAM_ERRMODE, PDO::ERRMODE_EXCEPTION);
    

    这样,您就不需要每次都显式检查错误,您try catch对整个事情使用单个块,并且您很好:

    try {
        insert_to_db($pdo, $table, $array_of_columns_and_values);
    }
    catch (\Exception $e) { //Will catch all kinds of exceptions, including PDOExceptions
        echo $e->getMessage();
    }
    
于 2012-05-08T14:57:03.760 回答
1

没有看到你的原始$columns_values数组是什么样子的。

希望能帮助到你

<?php 
function insert($table, $values){
    $dbh = $this->db_connect();

    $fieldnames = array_keys($values[0]);

    $sql = "INSERT INTO $table";
    /*** set the field names ***/
    $fields = '( ' . implode(' ,', $fieldnames) . ' )';
    /*** set the placeholders ***/
    $bound = '(:' . implode(', :', $fieldnames) . ' )';
    /*** put the query together ***/
    $sql .= $fields.' VALUES '.$bound;

    //INSERT INTO testtable( id ,col1 ,col2 ) VALUES (:id, :col1, :col2 )

    /*** prepare and execute ***/
    $query = $dbh->prepare($sql);
    foreach($values as $vals){
        $query->execute($vals);
        /*  Array
        (
        [id]   =
        [col1] = someval1
        [col2] = Someval21
        )*/
    }

}
//Multi Insert
$insert = array(array('id'=>'','col1'=>'someval1','col2'=>'Someval21'),
                array('id'=>'','col1'=>'someval2','col2'=>'Someval22'),
                array('id'=>'','col1'=>'someval3','col2'=>'Someval23'),
                array('id'=>'','col1'=>'someval4','col2'=>'Someval24')
);

insert('testtable',$insert);
?>
于 2012-05-08T14:53:06.030 回答
1

您尚未检查您的 prepare() 是否实际成功:

$sql = "INSERT ....";
$stmt = $dbh->prepare($sql);
if (!$stmt) {
    die($sql . $dbh->errorInfo());
}

永远不要假设查询成功,尤其是当您完全动态地构建查询时。

于 2012-05-08T14:34:05.603 回答