복붙노트

[SQL] PHP SQL 명령문을 준비 얼마나 코드의 반복을 피하기 위해?

SQL

PHP SQL 명령문을 준비 얼마나 코드의 반복을 피하기 위해?

SQL PHP의 대부분의 예에서와 같은 내가 볼 것을 문을 준비 :

$sql = 'INSERT INTO tasks(task_name, start_date, completed_date) VALUES(:task_name, :start_date, :completed_date)';
$stmt = $this->pdo->prepare($sql);
$stmt->execute([
        ':task_name' => $taskName,
        ':start_date' => $startDate,
        ':completed_date' => $completedDate,
    ]);

필드 이름은 거의 반복 ... 4 번!

나는이 각각 다른 의미를 가지고 이해하지만 여전히이 중복 정말 성가신 : 우리는 쿼리에서 뭔가를 변경하려는 경우, 우리는 4 시간을 변경해야합니다!

어떻게 PHP에서 너무 많은 중복을 피하고 더 나은 준비된 명령문을 가지고?

해결법

  1. ==============================

    1.아주 좋은 질문이고 나는 그것을위한 몇 가지 답이있다.

    아주 좋은 질문이고 나는 그것을위한 몇 가지 답이있다.

    우선, 당신은 쿼리의 필드 절을 생략 (그리고 누락 된 필드의 값 절에 기본 값을 추가) 및 위치 자리 표시자를 사용하여처럼 상세를 줄이기 위해 몇 가지 트릭을 사용할 수 있습니다 :

    $sql = 'INSERT INTO tasks VALUES(null, ?, ?, ?)';
    $this->pdo->prepare($sql)->execute([$taskName, $startDate, $completedDate]);
    

    그들은 항상 적용되지 않습니다 때문에 나는 그 트릭을 호출합니다.

    당신이 테이블의 모든 컬럼에 대한 값을 제공해야합니다. 그것은 테이블 정의에 정의 된 기본 값을 삽입합니다 있도록 DEFAULT (FIELD_NAME)로 가질 수, 생략 된 필드는 100 % 해당 만들기 위해, 단순히 널 (null) 값 또는 수 있습니다.

    다음 수준은 삽입을위한 도우미 함수 생성 될 것이다. 이 작업을 수행하는 경우, 하나의 필드 이름을 통해 SQL 인젝션의 잘 알고 있어야합니다.

    따라서, 이러한 도우미 함수는 자신의 도우미 기능이 있어야합니다 :

    function escape_mysql_identifier($field){
        return "`".str_replace("`", "``", $field)."`";
    }
    

    이러한 기능은 우리가 표 이름 및 데이터 어레이를 수용하는 도우미 함수를 만들 수있는 것은 필드 이름 => 값 쌍을 포함

    function prepared_insert($conn, $table, $data) {
        $keys = array_keys($data);
        $keys = array_map('escape_mysql_identifier', $keys);
        $fields = implode(",", $keys);
        $table = escape_mysql_identifier($table);
        $placeholders = str_repeat('?,', count($keys) - 1) . '?';
        $sql = "INSERT INTO $table ($fields) VALUES ($placeholders)";
        $conn->prepare($sql)->execute(array_values($data));
    } 
    

    이 코드를 짧은 수 있기 때문에 의도적으로 자리 표시 자 이름에 허용되지 않는 문자가있을 수 있습니다, 여기라는 이름의 자리 표시자를 사용하고 있지 않다 동안 열 이름, 공백이나 예를 들어 대시에 완벽하게 유효되고; 또한 우리는 일반적으로 내부 작동하는지 상관하지 않기 때문에.

    이제 삽입 코드가 될 것입니다

    prepared_insert($this->pdo, 'tasks',[
        'task_name' => $taskName,
        'start_date' => $startDate,
        'completed_date' => $completedDate,
    ]);
    

    많은 반복을 제거하므로으로

    그러나 나는 몇 가지 단점이 있습니다, 하나 위의 솔루션을 좋아하지 않는다.

    자동화에 대한 요구를 충족하기 위해, 나는 오히려 간단한의 ORM을 만들 것입니다. 그것은 어떤 그림이 아니라 괴물로하지 않은 용어에 의해 두려워하지 마십시오. 나는 특히 당신이 이미 OOP를 사용하고 주어진, 당신은뿐만 아니라 당신의 경우에 사용할 수 있도록 완전한 작동 예를 들어 최근에 게시합니다.

    그냥 삽입 () 메소드에 던져

    public function insert()
    {
        $fields = '`'.implode("`,`", $this->_fields).'`';
        $placeholders = str_repeat('?,', count($this->_fields) - 1) . '?';
    
        $data = [];
        foreach($this->_fields as $key)
        {
            $data[]  = $this->{$key};
        }
        $sql = "INSERT INTO `{$this->_table}` ($fields) VALUES ($placeholders)";
        $this->_db->prepare($sql)->execute($data);
    }
    

    그 후 당신이 당신의 클래스를 준비해야 할 것이다,

    class Task extends BaseDataMapper
    {
        protected $_table = "tasks";
        protected $_fields = ['task_name', 'start_date', 'completed_date'];
    }
    

    다음 - 모든 마법은 여기 일이! - 당신은 전혀 삽입 코드를 작성할 필요가 없습니다! 대신 속성에 할당 된 값을 클래스의 새로운 인스턴스를 생성하고 바로 삽입 () 메소드를 호출

    include 'pdo.php';
    $task = new Task($pdo);
    $task->task_name = $taskName;
    $task->start_date = $startDate;
    $task->completed_date = $completedDate;
    $user->insert();
    
  2. ==============================

    2.이는 가장 복잡한 예제를 중복되지 않습니다. 당신이 다른 PARAMS으로 쿼리를 여러 번 실행해야 할 때 준비된 명령문의 장점은 놀이에 더 온다.

    이는 가장 복잡한 예제를 중복되지 않습니다. 당신이 다른 PARAMS으로 쿼리를 여러 번 실행해야 할 때 준비된 명령문의 장점은 놀이에 더 온다.

    다음의 예는 1 내지 10의 값이 모든 행을 가져올 것이다 :

    $value = 1;
    $stmt = $pdo->prepare("INSER INTO (first, second, third) VALUES (?, ?, ?);");
    
    $rowsToInsert = [["first", "second", "third"]];
    
    foreach ($rowsToInsert as $row) {
      array_map($row, function($v, $i) use ($stmt) {
        $stmt->bindValue($i + 1, $v);
      });
    
      $stmt->execute();
    }
    

    또한 당신은 바인드 PARAMS에 다른 PHP는 논리를 자유롭게 사용할 수 있습니다 :

    $params = [
     ":first" => $first,
     ":second" => $second,
     ":third" => $third
    ];
    
    $sql = sprintf(
      "INSERT INTO (first, second, third) VALUES (%s);", 
      implode(" ", array_keys($params))
    );
    
    $stmt = $pdo->prepare($sql);
    
    foreach ($params as $name => $value) {
      $stmt->bindValue($name, $value);
    }
    
    $stmt->execute();
    
  3. from https://stackoverflow.com/questions/58439799/how-to-avoid-code-repetition-with-php-sql-prepared-statements by cc-by-sa and MIT license