PHP SQL P198　忘れがちな箇所をお浚い

##**PHPから**

```php:all2.php
<?php
$pdo = new PDO ( 'mysql:host=localhost;dbname=shop;charset=utf8', 'staff', 'password' );
foreach ( $pdo->query ( 'select * from product' ) as $row ) {
	echo '<p>';
	echo $row ['id'], ':';
	echo $row ['name'], ':';
	echo $row ['price'];
	echo '</p>';
}
var_dump ( $pdo );
?>
```
###**PHPからselect文の実行**

![2017030701.png](https://qiita-image-store.s3.amazonaws.com/0/95187/f60395d6-448b-8317-a4b6-d41d04042074.png)

```php:例 
$pdo->query ( 'select * from product' )
```

メソッドを呼び出すには「**変数->メソッド**」のように
「**->**」を使って記述する。


---
###**取得したデータを1行ずつ処理する**

```php:
foreach ( $pdo->query ( 'select * from product' ) as $row ) {
・・・
}
```

データベースから取得したデータは複数行にわたる。
productテーブルを指定してselect文を実行すると複数行の商品データが返って来る。
複数行のデータを順に処理するにはforeachループのような繰り返し構文を使う必要がある。

queryメソッドとforeachループを組み合わせると複数行のデータを簡単に処理することができる。

- [x] 配列ではないのに何故_________________________________                           
・foreachは配列とオブジェクトをループして使うための構文。配列ではないが使いやすくするために
特別にforeachの反復処理で使えるように作られている。        
_________________________________________________________


###**query**
|　|PHPからSQL文を実行|
|:--|:--|
|<font color="red">SQL文を実行</font>|**PDOの変数->query('SQL文')**|
|<font color="red">メソッドを呼び出す</font>|**変数->メソッド**|
|<font color="red">queryメソッド(関数)</font> |引数に指定したSQL文をデータベースに対して実行する
|<font color="red">->(アロー演算子)</font>|メソッドを呼び出す

ここではqueryメソッドによって取得された複数行のデータが1行ずつ順番に変数$rowに代入されます。
「・・・」の部分では、$rowを使って1行分のデータを取得し、表示するなどの処理を行います。

---

###**例$row['id']**
###**指定した列のデータを取り出す**
取得した行から**id**を取り出すには、
**$row['id']**
のように記述する。

1行分のデータは配列形式で格納されている。
<font color="red">列を取り出すには列名を配列の添字に指定する。</font>

![2017030702.png](https://qiita-image-store.s3.amazonaws.com/0/95187/14913425-3da8-d1ee-1b8c-bd7b9c6c4f49.png)

取り出したid列のデータに「:」をつけて表示する。
例えばデータが「1」なら「1:」のように表示される。

```php:
echo $row['id'], ':';
```

```php
$pdo=new PDO('mysql:host=localhost;dbname=shop;charset=utf8',
	'staff', 'password');
foreach ($pdo->query('select * from product') as $row) {
	echo "<p>$row[id]:$row[name]:$row[price]</p>";
```

同様に行からname列を取り出し、「:」を付けて表示する。
例えば「松の実」ならば「松の実：」のように表示される。

```php:
echo $row['name'], ':';
```

最後に行からprice列を取り出して表示する。
例えば「700」のように表示する。

```php:
echo $row['price'];

```

以上の処理によって
「1:松の実:700」
のように各行を表示する。

<font color="blue">foreachループで繰り返すことで、最後の行までのデータを表示することができる。

###**指定した列のデータを取り出す(3通りの書き方)**

```php:test31-input.php
<?php require_once 'header.php';?>
<!-- <form action="test31.php" method="post"> -->
<!-- <form action="test31-output.php" method="post"> -->
<form action="test31-output2.php" method="post">
	<input type="text" name="keyword"> <input type="submit" value="検索">
</form>
<?php require_once 'footer.php';?>
```

```php:方法①test31.php
$pdo = new PDO('mysql:host=localhost;dbname=takahashi1;charset=utf8', 'takahashi', 'takahashi');
$stmt =$pdo->prepare('select * from words where word=?');
$stmt->execute(array($_POST['keyword']));
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
	echo $row['sense'];
}
```


```php:方法②test31-output.php
$pdo = new PDO('mysql:host=localhost;dbname=takahashi1;charset=utf8', 'takahashi', 'takahashi');
$stmt = $pdo->prepare('select * from words where word=?');
$stmt->execute(array($_POST['keyword']));
foreach($stmt->fetchAll() as $row2){
	echo $row2['sense'];
}
```


```php:方法③test31-output2.php
$pdo = new PDO('mysql:host=localhost;dbname=takahashi1;charset=utf8','takahashi','takahashi');
$stmt = $pdo->prepare('select * from words where word=?');
$stmt->execute(array($_POST['keyword']));
foreach ($stmt as $row){
\\	var_dump($stmt);
	echo $row['sense'];
}
```

![20170317.png](https://qiita-image-store.s3.amazonaws.com/0/95187/c6a9afdf-d2c2-4b34-f89f-bccad8071894.png)

![201703172.png](https://qiita-image-store.s3.amazonaws.com/0/95187/662a1ade-45f4-3b8e-482f-a46e98b0d4d8.png)


###**fetchAllをfetchに置き換え**

```php:login-output.php置き換え前
 foreach ( $stmt->fetchAll() as $row ) {
	$_SESSION ['customer'] = array (
			// idというキーで$row['id']を入れる
			'id' => $row ['id'],
			'name' => $row ['name'],
			'address' => $row ['address'],
			'login' => $row ['login'],
			'password' => $row ['password']
	);
}
```

```php:これでもいい
foreach ( $stmt as $row ) {
	$_SESSION ['customer'] = array (
			// idというキーで$row['id']を入れる
			'id' => $row ['id'],
			'name' => $row ['name'],
			'address' => $row ['address'],
			'login' => $row ['login'],
			'password' => $row ['password']
	);
```

1行ずつ、連想配列形式で取り出すことを指示し、返り値を $result に代入する

```php:login-output.php置き換え後
while ( $row = $stmt->fetch ( PDO::FETCH_ASSOC ) ) {
	$_SESSION ['customer'] = array (
			// idというキーで$row['id']を入れる
			'id' => $row ['id'],
			'name' => $row ['name'],
			'address' => $row ['address'],
			'login' => $row ['login'],
			'password' => $row ['password']
	);
}
```

```php:login-output.php
<?php require 'header.php'; ?>
<?php require 'menu.php'; ?>
<?php
session_start ();
// unset→指定した変数を破棄する
unset ( $_SESSION ['customer'] );
$pdo = new PDO ( 'mysql:host=localhost;dbname=takahashi1;charset=utf8', 'takahashi', 'takahashi' );
$stmt = $pdo->prepare ( 'select * from customer where login=? and password=?' );
// var_dump($stmt);
$stmt->execute ( array (
		$_POST ['login'],
		$_POST ['password']
) );

// foreachは配列とオブジェクトをループして使うための構文
// 配列ではないが使いやすくするために特別にforeachの反復処理で使えるように作られている
// $rowという変数に入れる
// $rows = $stmt->fetchAll ();
// var_dump($rows)
// foreach ( $stmt->fetchAll() as $row ) {
while ( $row = $stmt->fetch ( PDO::FETCH_ASSOC ) ) {
	// foreach ( $rows as $row ) {
	// 連想配列$_SESSION['customer']にキーを指定して追加し、値として連想配列を代入
	$_SESSION ['customer'] = array (
			// idというキーで$row['id']を入れる
			'id' => $row ['id'],
			'name' => $row ['name'],
			'address' => $row ['address'],
			'login' => $row ['login'],
			'password' => $row ['password']
	);
}
if (isset ( $_SESSION ['customer'] )) {
	echo 'いらっしゃいませ、', $_SESSION ['customer'] ['name'], 'さん。';
} else {
	echo 'ログイン名またはパスワードが違います。';
}
?>
<?php require 'footer.php'; ?>
```

---

■解説■

```php
while ( $row = $stmt->fetch ( PDO::FETCH_ASSOC ) ) {
	$_SESSION ['customer'] = array (
			// idというキーで$row['id']を入れる
			'id' => $row ['id'],
			'name' => $row ['name'],
			'address' => $row ['address'],
			'login' => $row ['login'],
			'password' => $row ['password']
	);
}
```

1行ずつfetchして```$row```に設定して、$rowの中身をループの中で毎回処理して、
中身が無くなったらfetchの返り値がfalseになってループを抜ける感じ。
while(条件式)→カッコ内の条件式がTRUEの間繰り返される。

---

##**わからないことばメモ**

###**PDOStatementって何？**
プリペアドステートメントを表す。
ステートメント実行時は関連する結果セットを表す

###**プリペアドステートメントって何？**
SQLを使う際に、その条件とか値が異なるばあい、
それをパラメータ化して色んな値や条件で使いまわしできるもの。

[参考サイト](http://qiita.com/tabo_purify/items/d1166236f3b03c7be60d)

###**PDOクラス**
![2017030801.png](https://qiita-image-store.s3.amazonaws.com/0/95187/3c4b5492-9be7-9da9-4823-839441f1c637.png)

###**PDOStatementクラス**
![2017030902.png](https://qiita-image-store.s3.amazonaws.com/0/95187/4455ce3b-1fa6-759a-5ccd-b8ec5151d881.png)

■prepareメソッドが返したPDOStatementインスタンスを見たいのでvar_dumpしてみた

```php:
$pdo = new PDO ( 'mysql:host=localhost;dbname=takahashi1;charset=utf8', 'takahashi', 'takahashi' );
$stmt = $pdo->prepare ( 'select * from customer where login=? and password=?' );
var_dump($stmt);
$stmt->execute ( array (
		$_POST ['login'],
		$_POST ['password']
) );

// foreachは配列とオブジェクトをループして使うための構文
// 配列ではないが使いやすくするために特別にforeachの反復処理で使えるように作られている
// $rowという変数に入れる
$rows = $stmt->fetchAll ();
var_dump($rows)
```

<pre>
■実行結果
object(PDOStatement)#2 (1) { ["queryString"]=> string(51) "select * from customer where login=? and password=?" } array(0) { }
</pre>

####**queryString**
PDOStatementのプロパティ

```php:この中の
$pdo = new PDO('mysql:host=localhost;dbname=takahashi1;charset=utf8','takahashi','takahashi');
$stmt = $pdo->prepare('select * from words where word=?');
$stmt->execute(array($_POST['keyword']));
foreach ($stmt as $row){
	echo $row['sense'];
}
```

```php:queryStringにこれが格納されている
select * from words where word=?
```

###**PDOExceptionクラス**
![20170322.png](https://qiita-image-store.s3.amazonaws.com/0/95187/a4af9ac0-cf0a-bf42-a9e9-7de6df3f72a2.png)

###**Exception::getMessage**
例外メッセージを返す 

###**fetch**

<font color = "#ff0000">▪️PDOStatement::fetch([int フェッチモード = PDO::FETCH_BOTH])</font>
**フェッチモード**
フェッチモードとは結果セットから取り出したデータをどのような形式の変数に格納するかを表すパラメータ

| 定数 | 取得の形式 | 値の取得(例) |
|:------------:|:------------:|:------------:|
| PDO::FETCH_ASSOC|連想配列|$row['name']|
|PDO::FETCH_NUM|一般配列|$row[0]|
|PDO::FETCH_BOTH|一般配列/連想配列|$row[0]/$row['name']|
|PDO::FETCH_OBJ|オブジェクト|$row->name|


|||
|:--|:--|
|**foreach(PDOの変数->fetchAll() as 結果を代入する変数)**|SQL文をexecuteメソッドで実行した結果を取得する
|**fetch()**|1件データを取得。結果セットから次の行を取得する。
|**fetchAll()**|結果データを全件まとめて配列で取得

###**PDO::FETCH_ASSOC**

|||
|:--|:--|
|**PDO::FETCH_ASSOC**|結果セットに返された際のカラム名で添字を付けた配列を返す
||連想配列
||値の取得(例)→$row['name']

![20170315.png](https://qiita-image-store.s3.amazonaws.com/0/95187/fe2db523-cb52-114a-324b-57e9fd936817.png)
[参考サイト](http://qiita.com/tabo_purify/items/d1166236f3b03c7be60d#pdofetch_assoc)
![カラム.png](https://qiita-image-store.s3.amazonaws.com/0/95187/066ed2fd-2ff0-493c-4525-240229e5549b.png)


```php
// foreach ( $stmt->fetchAll() as $row ) {
while ( $row = $stmt->fetch ( PDO::FETCH_ASSOC ) ) {
	$_SESSION ['customer'] = array (
			// idというキーで$row['id']を入れる
			'id' => $row ['id'],
			'name' => $row ['name'],
			'address' => $row ['address'],
			'login' => $row ['login'],
			'password' => $row ['password']
	);
}
if (
```

![20170316.png](https://qiita-image-store.s3.amazonaws.com/0/95187/3c2de5d4-c212-1c3a-a903-9522514a0dad.png)

$rowにfetchで取れた```id name address login password```などの中身が代入されて、
$rowの中身がある限りの間繰り返すということ。


###**結果セット**
![結果セットとはpng.png](https://qiita-image-store.s3.amazonaws.com/0/95187/4eca9a1a-3313-f262-22a1-2f4dd3c72a0e.png)

![結果セット.png](https://qiita-image-store.s3.amazonaws.com/0/95187/cbb98765-eb0a-6144-1fcd-9bf6d1500191.png)