PDOを使ったPHPでのデータベース基本操作


PHPでデータベースを操作する方法をまとめました。簡易な解説なので、プログラムの日が浅い人は理解できないかもしれません。復習用としてお使いください。

PHPでデータベースを操作する場合は、まずPDOオブジェクトを生成します。この時はコンストラクタでデータベース情報を設定しておきます。 後は、そのPDOオブジェクトのメソッドでデータベースを操作するだけです。今回は、$dbhという変数でPDOオブジェクトを管理しています。

![図：PDOオブジェクト01](https://qiita-image-store.s3.amazonaws.com/0/62881/75bf5daa-5ed2-eb98-20fa-867a986265f8.gif "PDO-Object01.gif")

### データベース接続に必要な情報

まずはサンプルコードです。

```php
<?php
define('DB_HOST', 'DBの場所');
define('DB_NAME', 'DBの名前');
define('DB_USER', 'ユーザー名');
define('DB_PASSWORD', 'パスワード');

// 文字化け対策
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND=>"SET CHARACTER SET 'utf8'");

// PHPのエラーを表示するように設定
error_reporting(E_ALL & ~E_NOTICE);

// データベースの接続
try {
     $dbh = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASSWORD, $options);
     $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
     echo $e->getMessage();
     exit;
}

// ここからデータベースを操作します
?>
```

最初に接続に使うDB情報を定数で用意。変数でもOK

```php
define('DB_HOST', 'DBの場所');
define('DB_NAME', 'DBの名前');
define('DB_USER', 'DBのユーザー名');
define('DB_PASSWORD', 'パスワード');
```

[PHPBook](http://www.phpbook.jp/tutorial/pdo/index3.html)を見たところ1,2行目はDSNとしてまとめていました。

```php
$dsn = 'mysql:dbname=uriage;host=localhost'
```

つまり、以下のように書き換えれます。こちらの方が覚えやすいと思うので、これからこちらの表記を使いたいと思います。

```php
define('DB_DSN', 'mysql:dbname=DB_名前;host=DB_の場所');
define('DB_USER', 'ユーザー名');
define('DB_PASSWORD', 'パスワード');
```

### 文字化け対策

今回はXAMPPを利用しているのですが、データベースのセルに日本語が含まれていると文字化けが発生しました。  
原因が全然わからないのですが、PDOコンストラクタ、つまりPDOオブジェクトを作成するときに、次の引数を入れればいいみたいです。

```php
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND=>"SET CHARACTER SET 'utf8'")
```

以下のサイトでは5つの実験が記述してあり考察に参考になると思います。

[PDOでMySQL接続したら文字化けした時のメモ](http://blog.machacks.net/2013/06/18/pdo%E3%81%A7mysql%E6%8E%A5%E7%B6%9A%E3%81%97%E3%81%9F%E3%82%89%E6%96%87%E5%AD%97%E5%8C%96%E3%81%91%E3%81%97%E3%81%9F%E6%99%82%E3%81%AE%E3%83%A1%E3%83%A2/)

### エラーを確認する

PHPはエラーを表示しないのが標準設定らしいので、自分で設定を変更しなければいけません。そこで次の一文でPHPのエラーを表示させます。

```php
error_reporting(E_ALL & ~E_NOTICE)
```

また、データベースのエラー表示は次のように別途記述します。

```php
dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
```

これはPDOの設定PDO::ATTR_ERRMODEにPDO::ERRMODE_EXCEPTIOを設定しています。  
詳しいくことはPHPマニュアルに載っています。

> *   PDO::ATTR_ERRMODE: エラーレポート
> *   PDO::ERRMODE_EXCEPTION: 例外 を投げる
> 
> 引用元：<cite>[phpマニュアル - PDO::setAttribute](http://php.net/manual/ja/pdo.setattribute.php)</cite>

### 基本の４つのSQL文

SQL文は次の3種類に分かれます。

1.  DDL（Data Definition Language - データ定義言語）
    *   CREATE
    *   DROP
    *   ALTER
2.  DML（Data Manipulation Language - テータ操作言語）
    *   SELECT
    *   INSERT
    *   UPDATE
    *   DELETE
3.  DCL（Data Contorol Language - データ制御言語）
    *   COMMIT
    *   ROLLBACK
    *   REVOKE

とりあえず、データベースの操作をしたいのなら2番目のDMLを覚えておけばいいと思います。これが一番使うので。

次のテーブルを使ってサンプルを記しておきます。

<table><caption>テーブル名：Shohin_table</caption>

<thead>

<tr>

<th>商品ID</th>

<th>商品</th>

<th>価格</th>

<th>メーカー</th>

<th>発売日</th>

</tr>

</thead>

<tbody>

<tr>

<td>0001</td>

<td>ゲーム機</td>

<td>18,000</td>

<td>XXクリエイティブ</td>

<td>2012-06-14</td>

</tr>

<tr>

<td>0002</td>

<td>包丁</td>

<td>5.600</td>

<td>一刀入魂</td>

<td>2011-04-11</td>

</tr>

<tr>

<td>0003</td>

<td>コンロ</td>

<td>3,400</td>

<td>かかじん</td>

<td>2011-04-11</td>

</tr>

</tbody>

</table>

**１追加**

2013年4月1日発売の2,800円のゲームソフトと、  
2013年5月20日発売の5,000円の高級和菓子を追加したい。

**２更新**

ゲーム機の発売日が２ヶ月延期したのでデータを更新したい。  
それとお詫びとして値段を500円引く事になった。

**３削除**

商品のコンロが発売中止になったので、削除したい。

**４閲覧**

上司に次のようにデータベースを表示するように言われた。

1.  発売日の古い順にする。
2.  同じ発売日の場合は、値段の安い順にする。
3.  商品IDとメーカーは表示させなくてよい

この４つの操作は次のようなSQL文を書きます。

```mysql
-- １追加
INSERT INTO Shohin_table VALUES ('ゲームソフト', '2800', '2013-04-01'),
                               ('高級和菓子', '5000', '2013-05-20');
-- ２更新
UPDATE Shohin
     SET '発売日' = '2012-08-14',
          '価格'    = '17,500' 
  WHERE '商品ID' = '0001';

-- ３削除
DELETE FROM Shohin_table
 WHERE '商品ID' = '0003';

-- ４閲覧
SELECT '商品', '価格', '発売日'
  FROM Shohin_table
```

注意点としては、WHEREでどのレコード（行）が対象かを決めないと、全部のレコードに対して実行されます。１つのレコードに対して操作するならIDを条件としておくといいでしょう。（IDが被らない場合）

### PDOでSQL文を実行する

SQL文を実行する方法は２種類

<span style="color: #ff0000;">**※本来カラム名は日本語は使用できません。今回はわかりやすいように日本語で表記していますが、このままだとエラーが出ると思います。SQL文、データベースのカラム名は英数字で記述して下さい。**</span>

[**query**](http://jp1.php.net/pdo.query)

```php
$dbh->query(’ここにSQL文を書く’);

// SQL文とその中のパラメータを変数にすることもできる
$sql = 'SELECT  '商品', '価格' WHERE '商品ID' = $shohin_id';
$dbh->query($sql);
```

SQL文を即時実行、１回しか使わないならqueryメソッドを使うといいです。パラメータに変数を使うことで、より柔軟にすることもできますが、実はSQLを使いまわす用のメソッドもあります。それがprepareメソッドです。使い方は２通りあります。

[**prepare**](http://php.net/manual/en/pdo.prepare.php)

```php
// パターン１：変数を?で代用する
$dbh->prepare("UPDATE Shohin
                    SET '価格' = ? 
                    WHERE id = ?");

// パターン２：変数名の$をコロンに変える
$dbh->prepare("UPDATE Shohin
                    SET '価格' = :kakaku 
                    WHERE id = :id");
```

このように?（クエスチョンマーク）と:（コロン）でどの部分を後で置き換えるかを決めておきます。prepareはSQL文の準備をするメソッドで、実行するにはexcuteメソッドを使います。

```php
$stmt = $dbh->prepare('SQL文');

// ?を置き換える場合
$stmt->execute(array(500, 2));
// :（コロン）を置き換える場合
$stmt->execute(array(':kakaku'=>500, ':id'=>2));
```

executeメソッドを実行したことで、queryメソッドを実行したことと同じになります。また、ここで`stm`という変数がでてきましたが、ここにはexcuteの戻り値が入っています。query,prepare,excuteはともにPDOStatementオブジェクトというものが返されます。このオブジェクトはデータベースから引っ張ってきた情報をPHPで出力、つまりサイトの画面に表示したり、計算に使うために必要です。

### データを出力する

queryやexcuteメソッドでSQL文を実行しただけでは、その結果が戻り値として返されるだけで、値としてはまだ使えません。そこでfetchメソッドを使います。

<table>

<thead>

<tr>

<th>商品</th>

<th>価格</th>

</tr>

</thead>

<tbody>

<tr>

<td>ゲーム機</td>

<td>18,000</td>

</tr>

<tr>

<td>包丁</td>

<td>5.600</td>

</tr>

<tr>

<td>コンロ</td>

<td>3,400</td>

</tr>

</tbody>

</table>

**[fetch](http://php.net/manual/en/pdostatement.fetch.php)**

fetchメソッドは引数にデータの取り出し方のオプションを決めるのですが、これはprepareで?か:（コロン）と似たようなものです。それでは例を見てましょう。

データはSELECT文で以下のようなデータを引っ張ってきたとします。それを`stm`に入れています。

```php
// $stmtには既にSQL文を実行した結果が入っているとする
// パターン１
$result = $stmt->fetch(PDO::FETCH_NUM));
print($result[0]);
print($result[1]);

// パターン２
$result = $stmt->fetch(PDO::FETCH_ASSOC);
print($result['id']);
print($result['name']);
```

この場合の結果はどちらも`ーム機1800`と表示されます。

fetchメソッドは１行ずつ結果を取り出すので、全部を取り出す場合にはどちらかのパターンをループで回します。

```php
while($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
    print($result['id']);
    print($result['name']);
}
```

このようにすることで、$stmtの中のレコード（行）が１行ずつ取り出されて表示されていき、いずれ$stmtの中のレコードが空となり、ループは終了します。

### まとめ

PHPでデータベースを操作するにはPDOオブジェクトを使って、SQL文の実行、データの管理、取り出しを行います。これを図で俯瞰してみると次のようになります。

![図：PDOオブジェクト02](https://qiita-image-store.s3.amazonaws.com/0/62881/14ca3467-d262-c9a2-9bf9-324b34a0eba7.gif "PDO-Object02.gif")


さらに復習したい方はこちらの記事がおすすめです。ざっくりとまとまっていて見やすいです。

[はじめてPDOを使う人が知っておきたい 6 + 1 のポイント](http://kwsktr.hatenablog.com/entry/20110328/1301254129)