プリペアドステートメントを利用してデータを取得する方法について解説！

# はじめに
- プリペアドステートメントを利用してデータを取得する方法について本やネットの情報から調べて理解したことをまとめました。
- もし、書いていることに何か間違いがある場合はご指摘いただけると嬉しいです。

# プリペアドステートメントとは
- SQL文で値がいつでも変更できるように、変更する箇所だけ変数のようにした命令文を作る仕組みのことです。

## プリペアドステートメントの役割
- 以下のようなテーブルがあると仮定してプリペアドステートメントの役割について解説します。

**テーブル名：** users

|  name  |  email  |
| ---- | ---- |
|  てすと太郎  |  test-taro@test.test  |
|  やまだ太郎  |  yamada-taro@test.test  |
|  ごとう太郎  |  goto-taro@test.test  |

データの取得には、次のようなSQL文を使います。

### 特定の条件を満たすレコードを取得する

```sql
select フィールド名 from テーブル名 where 条件;
```

例えば、nameの値が`てすと太郎`さんのデータを取得する場合、次のように書きます。

```sql
select * from users where name="てすと太郎";
```

次にnameの値が`やまだ太郎`さんのデータを取得します。

```sql
select * from users where name="やまだ太郎";
```

最後に、nameの値が`ごとう太郎`さんのデータを取得します。

```sql
select * from users where name="ごとう太郎";
```

- このように、値が変化しているだけで、値以外のSQL文は変わっていません。
- 値がいつでも変更できるように、変更する箇所だけ変数のようにした命令文を作る仕組みのことをプリペアドステートメントと呼びます。

```sql
SELECT name FROM user WHERE name = :name;
```
- `:name`のように変化する値の部分を確保しておくことを**プレースホルダ**と呼びます。

- `:name`の部分に値を割り当てることを**バインド**と呼びます。


# プリペアドステートメントを利用してデータを取得する方法

以下の流れで実行していきます。

## 手順
**1.PDOでデータベースに接続する（PDOクラスをインスタンス化）**
**2.SQL文を実行する準備をする（prepareメソッド）**
**3.値をバインドする（bindValueメソッド）**
**4.プリペアドステートメントを実行する（executeメソッド）**
**5.データを配列で取得する（fetchメソッド）**

以下のようなデータベースとテーブルがあると仮定して解説します。

**データベース名：** test_db1
**テーブル名：** users

|  name  |  email  |
| ---- | ---- |
|  てすと太郎  |  test-taro@test.test  |
|  やまだ太郎  |  yamada-taro@test.test  |
|  てすと太郎  |  test-taro@taro.taro  |
|  やまだ太郎  |  test-yamada@yamada.yamada|

### 1.PDOでデータベースに接続する
```php
$user = "ここにユーザー名が入ります";
$password = "ここにパスワードが入ります";

$dbh = new PDO("mysql:host=localhost; dbname=test_db1; charset=utf8", "$user", "$password");
```
データベース接続について詳しくは[こちら](https://qiita.com/e2_waka/items/fac99da7bb3d0b39878c)に書いてます。

### 2.SQL文を実行する準備をする
- [PDO::prepare](https://www.php.net/manual/ja/pdo.prepare.php)メソッドを使ってSQL文を実行する準備をします。


#### 書き方 
```php:
$stmt = $dbh->prepare('SQL文')
```
#### コード例
```sql
$stmt = $dbh->prepare('SELECT * FROM users WHERE name = :name');
```

### 3.値をバインドする
- 値を割り当てるには、[PDOStatement::bindValue](https://php.net/manual/ja/pdostatement.bindvalue.php)メソッドを使います。（[PDOStatement::bindParam](https://php.net/manual/ja/pdostatement.bindparam.php)メソッドでもできますが、ここでは説明しません）
- bindValueメソッドを使うときは、下記のように記述します。

#### 書き方
```php
bindValue(パラメータID,バインドする値,データ型）
```
- 第1引数には名前付きプレースホルダの場合は`:name`と入力します。
- 第2引数にはバインドする値を指定します。値は直接入力するか、変数を入れます。
- 第3引数にはデータ型を指定します。定義済み定数は「[定義済み定数](https://php.net/manual/ja/pdo.constants.php)」で確認できます。指定しなかった場合は、`PDO::PARAM_STR（文字列型 ）`が指定されます。

#### コード例
```php
$stmt->bindValue(":name","てすと太郎",PDO::PARAM_STR);
```

## 4.プリペアドステートメントを実行する
プリペアドステートメントを実行するには、[PDOStatement::execute](https://php.net/manual/ja/pdostatement.execute.php)メソッドを使います。

```php
$stmt = $dbh->prepare('SELECT name FROM users WHERE name = :name');
$stmt->bindValue(":name","てすと太郎",PDO::PARAM_STR);
$stmt->execute();
```

## 5.データを配列で取得する
データを取得するには、[PDOStatement::fetch](https://php.net/manual/ja/pdostatement.fetch.php)メソッドまたは[PDOStatement::fetchAll](https://php.net/manual/ja/pdostatement.fetchall.php)メソッドなどを使います。

### fetchメソッドで配列として1行のみデータを取得する
fetchメソッドは該当するデータを配列として1行のみ取得します。

```php
$stmt = $dbh->prepare('SELECT * FROM users WHERE name = :name');
$stmt->bindValue(":name","てすと太郎",PDO::PARAM_STR);
$stmt->execute();

$result = $stmt->fetch();
print_r($result);
```


## fetchAllメソッドで配列として全てのデータを取得する
fetchAllメソッドは該当する全てのデータを配列として返します。

```php
$stmt = $dbh->prepare('SELECT * FROM users WHERE name = :name');
$stmt->bindValue(":name","てすと太郎",PDO::PARAM_STR);
$stmt->execute();

$result = $stmt->fetchAll();
print_r($result);
```
- `fetchメソッド`と`fetchAllメソッド`の引数に定数を指定することができます。
- 定数を指定することで、取り出したデータをどのように返すかを指定することができます。主な定義済み定数は下記になります。

|  定数  |  詳細  |
| ---- | ---- |
|  PDO::FETCH_ASSOC  | カラム名を付けた配列を返す  |
|  PDO::FETCH_NUM  |  0からはじまる添字を付けた配列を返す  |
|  PDO::FETCH_BOTH（デフォルト）	  |  カラム名と 0から始まる添字を付けた配列を返す  |

## fetchメソッドでの実行結果
```php
<?php

$user = "ここにユーザー名が入ります";
$password = "ここにパスワードが入ります";

$dbh = new PDO("mysql:host=localhost; dbname=test_db1; charset=utf8", "$user", "$password");
$stmt = $dbh->prepare('SELECT * FROM users WHERE name = :name');
$stmt->bindValue(":name","てすと太郎",PDO::PARAM_STR);
$stmt->execute();

$result = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($result);
```
```php:実行結果
Array ( [name] => てすと太郎 [email] => test-taro@test.test )
```
## fetchAllメソッドでの実行結果
```php
<?php

$user = "ここにユーザー名が入ります";
$password = "ここにパスワードが入ります";

$dbh = new PDO("mysql:host=localhost; dbname=test_db1; charset=utf8", "$user", "$password");
$stmt = $dbh->prepare('SELECT * FROM users WHERE name = :name');
$stmt->bindValue(":name","てすと太郎",PDO::PARAM_STR);
$stmt->execute();

$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($result);
```
```php:実行結果
Array ( [0] => Array ( [name] => てすと太郎 [email] => test-taro@test.test ) [1] => Array ( [name] => てすと太郎 [email] => test-taro@taro.taro ) )
```