본문 바로가기

PHP

[PHP] PDO로 쿼리하기

앞으로 티스토리 대신 blog.stackframe.dev에서 블로깅을 합니다. 이 블로그는 남겨 둘 예정입니다.

이전의 PDO로 데이터베이스 접속하기에 이어 이번에는 PDO를 사용하여 쿼리를 보내어 보겠습니다.

쿼리하는 방법으로는 크게 2가지 방법이 있는데, 첫 번째는 단순하게 완성된 SQL문을 보내서 결과를 받는 것과 Prepared statement로 코드 단에서 SQL문의 뼈대만 먼저 보내고 이후에 조건에 들어가는 인자들을 넘기는 것으로 SQL을 실행하는 방법이 있습니다. 여기서는 이 2가지 방법을 모두 설명할 예정입니다.

 

PHP에서 PDO로 DBMS에 접속하는 방법에 대해서는 이전 글을 참조하시기 바랍니다.

 

예제를 보는게 가장 이해하기 쉬우니 간단한 테이블을 하나 만들고 입력, 조회하는 PHP 코드를 만들어 보겠습니다.

<?php
include 'dbconn.php';

$pdo->query('CREATE TABLE IF NOT EXISTS test_table (idx integer, value text)');
$pdo->query('TRUNCATE test_table');

$insert_data_stmt = $pdo->prepare('INSERT INTO test_table (idx,value) VALUES (:idx,:value)');
for($i = 0;$i < 5;$i++)
{
	$insert_data_stmt->bindValue(':idx',$i,PDO::PARAM_INT);
	$insert_data_stmt->bindValue(':value','bindValue('.$i.')',PDO::PARAM_STR);
	$insert_data_stmt->execute();
}

$select_data_stmt = $pdo->prepare('SELECT * FROM test_table ORDER BY idx ASC');
$select_data_stmt->execute();
$result = $select_data_stmt->fetchAll(PDO::FETCH_ASSOC);

echo '==========<br>';
foreach($result as $row)
{
	echo $row['idx'], ' = ', $row['value'],'<br>';
}
echo '==========<br><br>';

$idx = 0;
$value = '';
$insert_data_stmt = $pdo->prepare('INSERT INTO test_table (idx,value) VALUES (?,?)');
$insert_data_stmt->bindParam(1,$idx,PDO::PARAM_INT);
$insert_data_stmt->bindParam(2,$value,PDO::PARAM_STR);
for($i = 5;$i < 10;$i++)
{
	$idx = $i;
	$value = 'bindParam('.$i.')';
	$insert_data_stmt->execute();
}

$select_data_stmt->execute();
$result = $select_data_stmt->fetchAll(PDO::FETCH_ASSOC);

echo '==========<br>';
foreach($result as $row)
{
	echo $row['idx'], ' = ', $row['value'],'<br>';
}
echo '==========<br><br>';

$select_odd_stmt = $pdo->prepare('SELECT * FROM test_table WHERE idx % ? = 1 ORDER BY idx');
$select_odd_stmt->bindValue(1,2);
$select_odd_stmt->execute();
$result = $select_odd_stmt->fetchAll(PDO::FETCH_ASSOC);
echo '==========<br>';
foreach($result as $row)
{
	echo $row['idx'], ' = ', $row['value'],'<br>';
}
echo '==========<br><br>';

실행 결과는 아래와 같습니다.

 

dbconn.php는 PDO로 데이터베이스 접속하기의 코드가 들어있습니다.

 

먼저 test_table 테이블이 없다면 테이블을 생성합니다. 컬럼은 idx와 value 2개 입니다. $pdo 객체의 query() 메소드를 사용하면 인자로 주어진 SQL문이 바로 실행됩니다. 이 메소드는 prepared statement가 아니므로 사용자가 입력한 값이 사용된다면 이스케이핑을 해야합니다.

그리고 TRUNCATE로 테이블을 비웁니다.

 

다음은 $insert_data_stmt 변수에 $pdo의 prepare() 메소드의 결과값을 저장합니다. prepare() 메소드는 prepared statement를 만드는 메소드입니다. 인자에는 SQL문이 들어갑니다만 :idx와 :value라는 이상한 값이 있습니다. 이 2개의 값은 바로 밑 for문 안의 bindValue()메소드에서 실제로 들어가는 값이 입력됩니다.

for문에서 bindValue로 :idx와 :value에 대한 값을 넣어주고 execute() 메소드로 실행하여 쿼리를 실행합니다.

이렇게 동일한 구조의 SQL을 실행한다면 prepared statement로 만들고 bind 후에 execute하는 것만 반복적으로 하면 되므로 DB단에서도 속도를 높힐 수 있고 코드에서도 복잡도가 줄어듭니다.

 

$select_data_stmt 변수에는 테이블 전체 데이터를 idx 오름차순 정렬해서 가져오는 prepared statement가 들어갑니다. 따로 들어갈 변수가 없으므로 그대로 execute()하면 실행됩니다. 그리고 데이터를 가져오기위해 fetchAll() 메소드를 사용하고 PDO::FETCH_ASSOC이란 값을 인자로 사용합니다. PDO::FETCH_*은 데이터를 어떻게 가져올건가를 지정합니다. 자세한 설명은 여기에 있습니다. 예제에서는 PDO::FETCH_ASSOC을 사용했으니 아래와 같은 모습의 데이터가 $result에 저장됩니다.

Array
(
    [0] => Array
        (
            [idx] => 0
            [value] => bindValue(0)
        )

    [1] => Array
        (
            [idx] => 1
            [value] => bindValue(1)
        )

    [2] => Array
        (
            [idx] => 2
            [value] => bindValue(2)
        )

    [3] => Array
        (
            [idx] => 3
            [value] => bindValue(3)
        )

    [4] => Array
        (
            [idx] => 4
            [value] => bindValue(4)
        )

)

다음으로는 또 insert하는 구문이 있습니다. 다만 이번에는 :idx, :value가 아닌 ?로 되어있고 bindValue가 아닌 bindParam 메소드가 사용되었습니다. 그리고 bindParam은 단 한번만 실행되고 for문 안에는 $idx와 $value 변수의 값만 변경한 뒤에 execute()합니다.

먼저 bindParam()의 첫 번째 인자는 위의 bindValue와 동일합니다. 다만 prepare 때 변수 정의 방법이 달라짐으로 인해 이번에는 숫자가 인자로 들어간 것입니다. 만약 prepare()에서 ?만으로 변수를 지정했다면 bindValue나 bindParam에서는 순서대로 1,2,3,4...로 입력해야 합니다. 첫 번째 insert 때처럼 문자로 변수를 지정하면 그 문자를 bindValue나 bindParam의 첫 번째 인자로 넣어줍니다.

bindParam은 변수의 참조를 두 번째 인자로 받습니다. C++의 참조를 생각하시면 됩니다. 그러므로 참조한 변수의 값이 바뀌면 execute()때 바뀐 값이 사용됩니다.

 

insert가 끝난 뒤에 $select_data_stmt을 다시 execute()하는데, 이걸보면 prepared statement를 사용하면 재사용성이 높아지는걸 알 수 있습니다.

 

마지막으로 select 하는 것도 위의 설명을 읽어보시면 간단히 이해가 되실겁니다.

'PHP' 카테고리의 다른 글

[PHP] PDO로 데이터베이스 접속하기  (0) 2019.04.29
htmlspecialchars로 XSS 공격 방어하기  (0) 2018.12.23