PDO

今回はPHPとデータベースを接続して、PHPでデータベースを操作できるようにします。
SQLも扱うので不安な方は一度、SQLを復習してからこの章に臨みましょう。

データベースを作成しよう

PHPとデータベースを接続するにあたってデータベースを新しく作成します。
まずはMySQLにログインしてSQLを実行できる状態にしておきましょう。

mysql -u root

ログインできたら db_app という名前のデータベースを作成しましょう。

CREATE DATABASE db_app;

使用するデータベースを宣言しておきましょう。

USE db_app;

最後にテーブルを作成しましょう。

CREATE TABLE contacts(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
email VARCHAR(100) NOT NULL,
body VARCHAR(255) NOT NULL
);

テーブルが作成できたらテーブルの構造も確認しておきましょう。

DESC contacts;

データベースに接続しよう

PHPとデータベースを接続するにはPDOを使用します。
PDO は PHP Data Objectsの略で、PHPにあらかじめ組み込まれたクラスなので新しくクラスを定義する必要はありません。

PDOクラスはインスタンスを生成するとき、接続先のデータベースの情報を引数に渡します。
引数に渡させる値を見ておきましょう。

引数パラメータ
1(必須)stringmysql:dbname=[データベース名];host=[ホスト名];charset=utf8
2stringデータベースのユーザー名
3stringデータベースのパスワード

※ MySQLではデフォルトでホスト名がlocalhostになります
※ 環境構築をするときにユーザー名はroot、パスワードなしに設定しています

PDOクラスの引数に渡せる引数が分かったので具体的な値を入れてみます。

引数パラメータ
1(必須)stringmysql:dbname=”db_app”;host=localhost;charset=utf8
2stringroot
3stringなし

この表を基にPHPのプログラムにしていきます。
まずはdb_app/pdo/study内にindex.htmlを作成し、以下のコードを記述してください。

<?php
// 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
$dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");

この記述だけでデータベースに接続できます。
しかし、このままでは正常にデータベースに接続できたのか分かりません。
そこで、try-catchを使用して、接続できなかった時にエラーメッセージを表示するようにします。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");
  echo "接続完了";
} catch(PDOException $e) {
  echo "エラーメッセージ : " . $e -> getMessage();
}

ここまでできたらプレビューしてみましょう。
接続完了が表示されれば成功です。

初めて try-catch が登場したので解説します。
try-catch は例外処理を検知し、その例外処理が発生したときにどうするかを決める構文です。
簡単にいうと、tryの中でエラーが発生したらcatchの中が動作するという構文です。

データベースに接続する処理をtryの中に含めることによって、
接続できなかったときにcatch内の処理が動作するようにしました。

catchでは検知するエラーの種類を選べます。
今回はPDOに関するエラーを検知したいのでPDOExceptionを使用しています。

データを挿入しよう

MySQLからログアウトした方はもう一度ログインしてください。

この後PHPで取得するデータを予め用意します。
SQLでデータを追加する方法は覚えていますか?
自信のない方はSQLの章に戻って復習しましょう。

以下の2つのSQLを実行し、データを追加してください。

INSERT INTO contacts (name, email, body) VALUES ("hoge", "hoge@hoge.com", "これはテストです");
INSERT INTO contacts (name, email, body) VALUES ("fuga", "fuga@fuga.com", "これはテストです");

SELECT文を実行して、追加したデータが表示されたOKです。

データを取得してみよう

PDOを使用してデータベースを操作するとき、予めSQLを準備しておきます。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");
  
  $sql = "SELECT * FROM contacts";

} catch(PDOException $e) {
  echo "エラーメッセージ : " . $e -> getMessage();
}

SQLの準備ができたので、PDOのインスタンスメソッドのqueryメソッドを使用してSQLを実行します。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");
  
  $sql = "SELECT * FROM contacts";

  // 慣習としての返り値がPDOStatementになるものはstmt(ステートメント)もしくはsth(ステートメントハンドル)にする
  $stmt = $dbh -> query($sql);
  
} catch(PDOException $e) {
  echo "エラーメッセージ : " . $e -> getMessage();
}

現段階でファイルを実行しても問題なくデータは取得できているのですが、
取得したデータを扱いやすくするためにもう少し処理を増やします。

PDOでSELECTする際には、fetchメソッドfetchAllメソッドでテーブルからデータを連想配列で取得することができます。

複数のデータを取得する場合はfetchAll、1つだけデータを取得する場合はfetchという風に覚えておきましょう。

fetchやfetchAllを使用する際に、取得したデータの形式を指定するモードがあります。
このモードのことをフェッチモードといいます。

フェッチモードはいくつか種類があるのですがまずは、 PDO::FETCH_BOTHPDO::FETCH_ASSOC の違いを理解しておきましょう。

PDO::FETCH_BOTH

フェッチモードを指定しない場合は PDO::FETCH_BOTH が適用されます。

連想配列のキーを連番カラム名で取得したい場合はこのモードを指定してください。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");
  
  $sql = "SELECT * FROM contacts";

  // 慣習としての返り値がPDOStatementになるものはstmt(ステートメント)もしくはsth(ステートメントハンドル)にする
  $stmt = $dbh -> query($sql);
  
  $contacts = $stmt -> fetchAll(PDO::FETCH_BOTH);
  
  echo "<pre>";
  var_dump($contacts);
  echo "</pre>";
} catch(PDOException $e) {
  echo "エラーメッセージ : " . $e -> getMessage();
}

以下のように、キーを連番とカラム名でデータを取得できます。

PDO::FETCH_ASSOC

連想配列のキーをカラム名で取得したい場合はこのモードを指定してください。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");
  
  $sql = "SELECT * FROM contacts";

  // 慣習としての返り値がPDOStatementになるものはstmt(ステートメント)もしくはsth(ステートメントハンドル)にする
  $stmt = $dbh -> query($sql);
  
  $contacts = $stmt -> fetchAll(PDO::FETCH_ASSOC);
  
  echo "<pre>";
  var_dump($contacts);
  echo "</pre>";
} catch(PDOException $e) {
  echo "エラーメッセージ : " . $e -> getMessage();
}

以下のように、キーをカラム名でデータを取得できます。

取得したデータを表示しよう

まずはファイルの記述を全て削除し、以下の記述にしてください。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");
  
  $sql = "SELECT * FROM contacts";

  // 慣習としての返り値がPDOStatementになるものはstmt(ステートメント)もしくはsth(ステートメントハンドル)にする
  $stmt = $dbh -> query($sql);
  
  $contacts = $stmt -> fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
  echo "エラーメッセージ : " . $e -> getMessage();
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <title>PDO</title>
</head>
<body>
 
</body>
</html>

取得したデータは配列になっているので、その中から要素を取り出すにはforechを使用します。
取り出した要素の中にあるバリューをHTMLに出力します。

まずは配列から要素を取り出す方法を記述します。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");
  
  $sql = "SELECT * FROM contacts";

  // 慣習としての返り値がPDOStatementになるものはstmt(ステートメント)もしくはsth(ステートメントハンドル)にする
  $stmt = $dbh -> query($sql);
  
  $contacts = $stmt -> fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
  echo "エラーメッセージ : " . $e -> getMessage();
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <title>PDO</title>
</head>
<body>
 <?php foreach($contacts as $contact): ?>

 <?php endforeach ?>
</body>
</html>

この記述の仕方は初めてなので、今まで学んできた記述の仕方とどう使い分けるのか解説します。

点数が80点以上であれば「合格です」、80点未満であれば「不合格です」とHTMLで表示するプログラムがあったとします。

パターン1

<?php
$score = 80;

if(80 <= $score) {
  echo "<p>合格です</p>";
} else {
  echo "<p>不合格です</p>";
}

パターン2

<?php
$score = 80;
if(80 <= $score):
?>
  <p>合格です</p>
<?php else: ?>
  <p>不合格です</p>
<?php endif; ?>

パターン1はechoによって出力された文字列の中にpタグとして認識される箇所が含まれていることによって、
HTMLがpタグとして判断して表示できるようにしています。

パターン2は予め表示したいHTMLを用意しておき、条件によってHTMLの表示内容を切り替えています。

PHPで処理した結果をHTMLに出力しなければならい場合はパターン2を使った方がシンプルでみやすいです。
WordPressでもこの書き方をするので覚えておきましょう。

配列から要素を取り出す処理が実装できたので、今度は取り出した要素の中身を確認してみましょう。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");
  
  $sql = "SELECT * FROM contacts";

  // 慣習としての返り値がPDOStatementになるものはstmt(ステートメント)もしくはsth(ステートメントハンドル)にする
  $stmt = $dbh -> query($sql);
  
  $contacts = $stmt -> fetchAll(PDO::FETCH_ASSOC);
} catch(PDOException $e) {
  echo "エラーメッセージ : " . $e -> getMessage();
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <title>PDO</title>
</head>
<body>
 <?php foreach($contacts as $contact): ?>
   <?php var_dump($contact) ?>
 <?php endforeach ?>
</body>
</html>

$contactは連想配列になっていることがわかりましたね。
次は連想配列の中から「name」「email」「body」の各項目を取り出して表示できるようにします。

<?php
try {
  // 慣習としてPDOインスタンスはdbh(データベースハンドルの略)にする
  $dbh = new PDO("mysql:dbname=db_app;host=localhost;charset=utf8", "root");

  $sql = "SELECT * FROM contacts";

  // 慣習としての返り値がPDOStatementになるものはstmt(ステートメント)もしくはsth(ステートメントハンドル)にする
  $stmt = $dbh->query($sql);

  $contacts = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
  echo "エラーメッセージ : " . $e->getMessage();
}
?>

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <title>PDO</title>
</head>

<body>
  <?php foreach ($contacts as $contact) : ?>
    <p>名前 : <?php echo $contact["name"] ?></p>
    <p>メールアドレス : <?php echo $contact["name"] ?></p>
    <p>お問い合わせ内容 : <?php echo $contact["name"] ?></p>
  <?php endforeach ?>
</body>

</html>

連想配列からバリューを取り出すときは、取り出したいバリューと対になっているキーを使えばよかったですね。
情報量が多くなってきたので少し整理します。

$contactsにはデータベースから取得した2つのレコードが配列形式で格納されています。

foreachで$contactsから要素を1つずつ取り出して、それを一時的に$contactという変数に格納しておきます。

今回表示したい値は「name」「email」「body」のキーと対になっているので、以下のようにすることで取得することができます。

$contact["name"];
$contact["email"];
$contact["body"];

一見難しく感じられますが、今まで学習してきたものが組み合わせなのです。
1回で理解できなくても大丈夫です。
何度も繰り返し勉強し、どこから理解できなくなったのか洗い出してみましょう。
その理解できなくなった箇所はこれまでに学習した箇所なのであとはそこを復習するだけです!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です