PDOを使ってPHPでMySQLに接続する

PDOについて、自分で理解するために調べた内容をまとめただけの備忘録です。
よりよい方法や間違い等ございましたら、アドバイスいただけると光栄です。

#前提条件
下記条件を前提に話を進めます。
* PHPは `PHP 5.3.6` 以上
* データベースは `MySQL`
* 文字エンコードは `UTF-8`

#PDOとは
「**P**HP **D**ata **O**bjects」の頭文字をとった名称です。

今まではデータベースの種類によって利用する関数を分けていました。

例えば、
MySQLへ接続する場合は「mysql_connect」関数で接続していましたし、
PostgreSQLの場合は「pg_connect」関数で接続していました。

データベースを固定している場合は問題がありませんが、
もし将来的に違うデータベースへの変更や移植もする場合には、
全て書き換えなくてはいけません。。。

しかし、PDOクラスを使用すれば、
どの**データベースを利用する場合でも同じ関数を使うことができます**ので、
もし将来データベースを変更することがあっても、
PDOクラスを作成する時に指定したパラメータだけを変更するばいいことになります。
（まあ、データベースによって若干の差異はあるそうですが。。。）

まずはPDOクラスを使ってデータベースに接続する方法を見ていきましょう。

#PDOでDBに接続
MySQLに接続するときは、下記のように記述します。（PHP5.3.6以降）

```php
$dsn = 'mysql:host={サーバー名};dbname={データベース名};charset={文字エンコード}';
$db_user = '{ユーザー名}';
$db_pass = '{パスワード}';
$driver_options = [
    変更したい属性 => 値,
    変更したい属性 => 値,
];

try {
    $pdo = new PDO($dsn, $db_user, $db_pass, $driver_options);
} catch (PDOException $e) {
    exit('データベース接続失敗。' . $e->getMessage());
}
```
引数中身を詳しく見ていきましょう。

## $dsn
データソース名(**D**ata **S**ource **N**ame)。データベースに接続するために必要な情報が含まれます。
MySQLの基本的な書き方を例に挙げます。

```
mysql:host={サーバー名};dbname={データベース名};charset={文字エンコード}
```
>
+ 頭にデータベースの種類を指定して `:` で区切る。
+ 各項目は **項目名=値** とし、`;` で区切る。

指定する各項目について、詳しく見ていきましょう。

### {サーバー名}
ホスト名（`localhost` など）またはIPアドレス（`127.0.0.1` など）を指定します。
一般的には

+ Linux環境は**ホスト名推奨**
+ Windows環境は**IPアドレス推奨**

となっております。

### {データベース名}
データベース名を指定します。
基本的には必須ですが、データベースを後で `USE test` のようにSQL文で選択する場合、省略することができます。

### {文字エンコード}
文字エンコードを指定します。
補足ですが、`UTF-8` ではなく `utf8` であることに注意してください。ハイフンは入りません。

また、PHP 5.3.5 以前の PDO では、ここで文字エンコードの指定が出来ません。
そのため、ドライバ固有の接続オプション（詳細については後述）での指定が必要になります。
詳しい方法などについては、こちらの記事にまとまっているので、おすすめです。

+ [PHP 5.3.6より前のバージョンの PDO MySQL で charset を指定する][pdo_char]

## $db_user
DSN文字列のユーザー名。ルート権限でのデフォルト値は、`root`です。

## $db_pass
パスワード。ルート権限でのデフォルト値は、空白です。

## $driver_options
接続時のオプションを連想配列で指定します。
それとは別に、PDOクラスをインスタンス化した後にオプションを設定することも可能です。

```php
$dsn = 'mysql:host={サーバー名};dbname={データベース名};charset={文字エンコード}';
$db_user = '{ユーザー名}';
$db_pass = '{パスワード}';

$pdo = new PDO($dsn, $db_user, $db_pass);
$pdo->setAttribute(変更したい属性 , 値);
$pdo->setAttribute(変更したい属性 , 値);
```

オプションの中には、インスタンス化のときだけしか設定できないものがあります。
特に理由がなければ、**インスタンス化するときに連想配列でオプションを設定するように**しましょう。

オプションとその値については、マニュアルにまとまっているのでおすすめです。

>[php マニュアル - PDO::setAttribute][pdo_options]

# PDOでSQL文を実行
PDOでSQL文を実行する際には、下記２種類のメソッドが使えます。

+ query
+ prepare

次に、各メソッドについて詳細を見ていきましょう。

## 1. queryメソッド
SQL文を即時実行、**１回しか使わない**ならqueryメソッドを使うといいです。

```php
$stmt = $pdo->query("SELECT * FROM `user`");
```
返されるオブジェクトは`PDOStatement`と呼ばれるオブジェクトで、`$pdo`の内容とは別のものですので注意してください。
このオブジェクトはデータベースから引っ張ってきた情報をPHPで出力、つまりサイトの画面に表示したり、計算に使うために必要です。

## 2. prepareメソッド
queryメソッドは、パラメータに変数を使うことでより柔軟にすることもできます。
しかし、実は**SQLを使いまわす**用のメソッドもあります。それがprepareメソッドです。
使い方は２通りあります。

```php
// パターン１：変数を?で代用する
$stmt = $dbh->prepare("SELECT * FROM `user` WHERE `user_name` = ? AND `age` = ?");
$stmt->execute(array('山田太郎', 22));

// パターン２：変数名の$をコロンに変える
$stmt = $dbh->prepare("SELECT * FROM `user` WHERE `user_name` = :user_name AND `age` = :age");
$stmt->bindValue(':user_name', '山田太郎');
$stmt->bindValue(':age', 22, PDO::PARAM_INT);
$stmt->execute();
```
`prepare`はSQL文の準備をするメソッドで、`excute`はそれを実行するメソッドです。
**executeメソッドを実行したことで、queryメソッドを実行したことと同じ**になります。

尚、`prepare` `excute`も、PDOStatementオブジェクトが返されます。

# データを出力
queryメソッドやprepareメソッドでSQL文を実行しただけでは、
PDOStatementオブジェクトに結果セット保持されているだけで、**値としてはまだ使えません**。
値を取得するには、`fetch`や`fetchAll`というメソッドを使用します。

```php
// PDOクラスをインスタンス化
$pdo = new PDO(...);

// PDOStatementオブジェクトに結果セット保持
$sql = "SELECT * FROM `user`";
$stmt = $pdo->query($sql);

// 値を取得
$results = $stmt->fetchAll();
```

fetchメソッド や fetchAllメソッドは、引数にオプションを入れて、様々な形で出力することができます。
よく使われるオプションとその値については、こちらの記事にまとまっているのでおすすめです。

>[PDOフェッチパターン大全][fetch]

# 参考資料
>
+ [php マニュアル - PDO::setAttribute][pdo_options]
+ [PHP 5.3.6より前のバージョンの PDO MySQL で charset を指定する][pdo_char]
+ [PDOフェッチパターン大全][fetch]
+ [はじめてPDOを使う人が知っておきたい 6 + 1 のポイント][pdo]

[fetch]:https://qiita.com/mpyw/items/d52351bd1a8068344cc2
[pdo]:http://kwsktr.hatenablog.com/entry/20110328/1301254129
[pdo_char]:https://qiita.com/ngyuki/items/d88a4df860abb51eb714
[pdo_options]:http://www.php.net/manual/ja/pdo.setattribute.php