こんにちは、takaです。
PHPでデータベースを操作するときに「fetch(PDO::FETCH_ASSOC)」みたいなコード、たまに出てきますね?
・・・正直、何をしてるか分からなくないですか?
僕は「『fetch』って日本語でいうと「〜を取ってくる」って意味だから、何かデータを取ってきているんだな」ぐらいの理解でいましたが、この「fetch」がわかるとデータベースの理解がぐっと深まります。
今回はこの初心者にとっていまいち分かりにくいPHPにおける「fetch」について説明していきたいと思います。
また、様々な種類がある「fetch」をどのように使い分けるのかも、実装したい機能から考える、ということから具体的にみていきます。
この記事を読むことで、よく分からずに使っていた「fetch」をしっかりと理解することが出来ますよ。
まずは構造を知る。
冒頭で紹介した「fetch(PDO::FETCH_ASSOC)」ですが、これは大きく2つのカテゴリーに分けることができます。
fetch・・・前半のこの部分は「どのようにデータを取ってきますか?」というデータの取り方を表す部分。
(PDO::FETCH_ASSOC)・・・後半のこの部分は「取ってきたデータをどのような形で格納しますか?」という部分。
なので、この前半部分と後半部分に「どんな種類があって、どんな働きがあるのか」ということを抑えておけば、「fetch」関連のことは大方わかるということになります。
まずは前半部分である「どのようにデータを取ってくるのか?」を見ていきましょう。
データの取り方は主に4種類。でもよく使うのは2つ。
データを取ってくる方法は主に次の4つです。
*()にあるのは、公式のリンクとなっています。
・fetch・・・該当するデータを1行返す。(fetch)
・fetchAll・・・該当するすべてのデータを配列で返す。(fetchAll)
・fetchColumn・・・該当するデータから単一のカラムを返す。(fetchColumn)
・fetchObject・・・該当するデータを1行取得して、それをオブジェクトとして返す。(fetchObject)
このうち、よく使用されるのは「fetch」と「fetchAll」です。
実際にどのようにデータが取得されるのかは、あとで詳しく見ていきます。
次に後半部分の「データをどのように格納するのか?」をご紹介します。
データの格納の仕方
後半部分は「データの格納の仕方」。これはもともとPHP側で定義されている「定義済み定数」を用いて決定していきます。
以前、こちらの記事でも紹介した「$_POST」のように予めPHP側で「これ用意してるから、使っていいよ!」というやつです。
こんにちは、takaです。 「$_POST」。 いきなり何だ、と思われるかもしれませんがこの変数しっかり分かってますか? PHPを学習する上で非常に重要な概念ですが、初心者がつまずく最初のところではないでしょうか[…]
<定義済み定数の種類>
-
PDO::FETCH_ASSOC・・・結果セットに 返された際のカラム名で添字を付けた配列を返します。
-
PDO::FETCH_BOTH (デフォルト)・・・結果セットに返された際のカラム名と 0 で始まるカラム番号で添字を付けた配列を返します。
- PDO::FETCH_NUM・・・結果セットに返された際の 0 から始まるカラム番号を添字とする配列を返します。
*上記で紹介した定数は「fetch」と「fetchAll」で使用できる定数となります。
またこれ以外にもまだまだ種類はたくさんありますが、今回はあえて3つに絞ってご紹介してます。
「他にも何があるのか気になる!」という方は、上記にある「データの取り方」でご紹介した公式のリンクにアクセスしていただき、「パラメーター」という部分をご参照ください。
これでfetchに関わる前半部分、後半部分の紹介が終わりました。
ここまで読んでみて、どうでしょう。
「ちっともイメージがわかない・・・」となっているのではないでしょうか。僕もこれだけ読んだときは、「で、結局どんな感じにデータは取得してるんですか?」と思いました。
次に見ていきたいのは、「fetch」と「fetchAll」をそれぞれ用いてデータの格納の仕方でご紹介した3つの定義済み定数を組み合わせることで、「どのようにデータが取得されるのか?」を詳しく見ていきます。
取得されるデータの中身を見ていこう!
まずはデータを引っ張ってくる元となるデータベースを用意します。
今回は下記のデータを用意しました。
このデータを取得するために、コードは下記のように記述しています。
<?php
try {
$dsn = 'mysql:dbname=php_sample01;host=localhost;charset=utf8';
$user = 'root';
$password = 'root';
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
);
$dbh = new PDO($dsn, $user, $password, $options);
$stmt = $dbh->prepare('SELECT * FROM users WHERE age >= 40');
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
//ここにある「fetch」や()の定義済み定数を変えていくよ!
print_r('<pre>');
print_r($result);
print_r('</pre>');
} catch (Exception $e) {
error_log('障害が発生しており、ご迷惑をおかけしています。');
}
?>
○SQL文について
→SQL文で、(‘SELECT * FROM users WHERE age >= 40’)としているので、ここでは「データベースの中から40歳以上のデータを選ぶ」という命令を出している、ということになります。
○<pre></pre>について
→print_r($result)を<pre>というタグで囲っていますが、これは出力結果を見やすくするためにつけてます。つけなくても問題はありませんが、結果がかなり見づらいので今回はこのようにしてます。
*上記のコードを見て、「そもそもPDOとかってなんですか?」という方はこちら。
こんにちはtakaです。 PHPを学習していく上で切っても切れない「データベース」との関係。 PDOやらtry~catchやら、最初に見た時は「何を言ってるの?」と感じた方、多いと思います。もちろん僕も。 今回の記事ではそんな[…]
fetchで取得されるデータをみてみよう
おさらい:fetch=該当するデータを1行返す
<fetch+FETCH_BOTH>
$result = $stmt->fetch(PDO::FETCH_BOTH);
<結果>
なんでこのようなデータになるのかを見てみると・・・
fetch = 該当するデータ、ここだとage(年齢)が40歳以上のデータを1行返すので一番初めの「鈴木太郎」さんが該当する
FETCH_BOTH = 「カラム名」と「0から始まるカラム番号で添字をつけた」配列の形式でデータを格納する。
簡単にいうと、連想配列の形式と通常の配列の形式の2つの配列をデータに格納するということ。だから「BOTH(両方)」という名前になっている。
<fetch+FETCH_ASSOC>
$result = $stmt->fetch(PDO::FETCH_ASSOC);
<結果>
fetch = 該当するデータを1行返す
FETCH_ASSOC = カラム名を添字にした配列形式(連想配列)でデータを格納する。
<fetch+FETCH_NUM>
$result = $stmt->fetch(PDO::FETCH_NUM);
<結果>
fetch = 該当するデータを1行返す
FETCH_NUM = 0から始まるカラム番号を添字としてデータを格納する。
と見てきたように、「fetch」は1行しかデータを取ってこない+配列の形式でデータが格納される、という形です。
今回のSQL文である「40歳以上のデータを取ってくる」だと、鈴木太郎さん以外にも高橋綾さんと橋下譲さんも該当しますが、あくまでfetchは「1行しか取ってこない」ので、結果は上記のようになります。
次に「fetchAll」を見てみましょう。
fetchAllで取得されるデータをみていこう
おさらい:fetchAll=該当するすべてのデータを配列の形式で返す
*どんな感じでデータが取得されるのか、これまでのことを参考にして考えてみてください。
<fetchAll + FETCH_ASSOC>
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
fetchAll = 該当するすべてのデータを配列の形式で返す
FETCH_ASSOC = カラム名を添字にした配列形式(連想配列)でデータを格納する。
さて今度は40歳以上の全ての方のデータを取得することが出来ました。さっき出番がなかった高橋さんと橋下さんもデータに格納されていますね。
でも、1つ不思議な部分があります。よーくみると、Arrayの中にさらにArrayという形でデータが格納されています。
これは、上記の赤線にあるとおりfetchAllもFETCH_ASSOCもどちらも配列の形式でデータを扱うからです。
この形を「二次元配列」と呼びます。
初見だとびっくりするかもしれませんが、単に配列の中に配列が入っているだけでそれぞれ番号の添字(背番号的なもの)が振られて管理されているだけです。
[0]だったら鈴木さんのデータ、[1]だったら高橋さんのデータ、といった具合です。
<fetchAll+FETCH_NUM>
$result = $stmt->fetchAll(PDO::FETCH_NUM);
<結果>
fetchAll = 該当するすべてのデータを配列の形式で返す
FETCH_NUM = 0から始まるカラム番号を添字としてデータを格納する。
カラム名だったところが数字に変わるだけ、でした。
*FETCH_BOTHはかなりみづらいので、上記2つの結果が足されたもの、としてお考えください。
実装したい機能から、使うべきfetchの組み合わせは決まる
ここまで、主に「fetch」と「fetchAll」を軸としてそれぞれのデータの格納の仕方を組み合わせて、実行結果を見てきました。
それで次に考えなくちゃいけないのは、「実際にコードを書くときは、どのように使い分ければいいのか?」ということだと思います。
この問いに対する答えは非常にシンプルです。
「実装したい機能によって、組み合わせを決める」
です。
まあ、当たり前なんですが・・・。
具体的にどういうことかを簡単に紹介します。
ログイン機能を実装したいときに、どの組み合わせでfetchを使う?
例えば「ログイン機能」をウェブ上で実装したいな、となった場合。
大まかな処理の流れは次のようになるかと思います。
① ユーザーにメールアドレス+パスワードを入力してもらう
② そのパスワードがちゃんとアドレスの形式とパスワードの形式になっているかのチェック(バリデーションチェック)
③ ②がOKなら、メールアドレスを基にしてデータベース(DB)に登録されているパスワードのデータを引っ張ってくる
④ DBから引っ張ってきたパスワードと、ユーザーに入力してもらったパスワードが本当にあっているのかをチェックする
⑤ もしパスワードが一致したら、ログイン成功。
といった流れです。
ここで注目して欲しいのは③の処理の部分で、「メールアドレスを基にして、DBからパスワードのデータを引っ張ってくる」というところ。ここで今回学んだ「fetch」くんが活躍します。
さてここで問題。上記の処理をするためには、今回学んだ「fetch」の中でどのように組み合わせてデータを取ってくればいいのでしょうか。
答え
fetch(PDO::FETCH/ASSOC)
となります。
なので、実装したい機能の流れを洗い出すなかで「ここはDBからデータを取ってくる必要があるけど、この場合はfetch、この場合はfetchAll」といった具合で選択する、という感じです。
難しいことでも、きっとわかるようになる。
一番初めにfetch(PDO:FETCH_ASSOC)と見たときの衝撃は忘れません。
ちなみにそのときのこともブログに書いていますが、本当何もわかってません(笑)
Webサービス部 Lesson10/ 2hour Sep / 2hour Total / 103.5 hour 目次 1 FETCH_ASSOCとは何か? FETCH[…]
でも、学習を進めるにつれてこれが何を意味しているのか、調べながら徐々に理解することができました。
これからもこうしたことが沢山出てくるかと思います。
その都度挫折しそうになりますが、「まあそのうち学習が進めば理解できるだろう」という気持ちで取り組めば大方大丈夫です。
この記事で少しでもみなさんの「わからん!」が減ってくれると嬉しいです。
最後までありがとうございました。
ではまた!