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 オブジェクトをインスタンス化しません。関数が機能するには 1 つ必要なので、引数の 1 つにする必要があります。
  2. エラーが発生した場合はExceptionをスローします。これは、エラーを処理するためのより良い方法です。
  3. 名前のないプレースホルダー ( vs )の代わりに名前付きのプレースホルダーを使用します。デバッグが必要になった場合に備えて、より読みやすく、追跡しやすいクエリを生成します。:name?
  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、全体に 1 つのブロックを使用するだけで済みます。

    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 に答える