PDO実装

DBに接続する関数をつくる


この研修では、htdocs/LetsEngineer/curriculum/3-2というフォルダの中に課題を作成してください。

3-2フォルダにdb_connect.phpを作成します。
PDOについてで作成したdb_connect.phpを編集していただいても問題ありません。)
db_connect.phpには下記をコピペしてください。

<?php
// DB名
define('DB_DATABASE', 'yigroupBlog');
// MySQLのユーザー名
define('DB_USERNAME', 'root');
// MySQLのログインパスワード
define('DB_PASSWORD', 'root');
// DSN
define('PDO_DSN', 'mysql:host=localhost;charset=utf8;dbname='.DB_DATABASE);

/**
 * DBの接続設定をしたPDOインスタンスを返却する
 * @return object
 */
function db_connect() {
    try {
        // PDOインスタンスの作成
        $pdo = new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD);
        // エラー処理方法の設定
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch(PDOException $e) {
        echo 'Error: ' . $e->getMessage();
        die();
    }
}

さて、ほとんどのことはPDOについてで解説しております。
今回初めて出てきた用法について解説していきます。

関数としてひとまとめにする


DBからデータを取得したり、新規作成したり、更新したりする作業は至るところで発生します。
そのため、 何度も書くことになりそうなコード はあらかじめ関数にしておきます。
関数自体は既に関数でも学習したことと思います。

/**
 * DBの接続設定をしたPDOインスタンスを返却する
 * @return object
 */
function db_connect() {

    // 省略

}

関数の名前は正直何でも良いのですが、分かりやすい名前をつけておくことがベターです。
今回はDBに接続する関数なので、db_connect()としました。

また、頭についているコメントアウトの部分ですが、今は学習しなくても良いです。
このように関数の説明書きなどを用意しておくと、チーム開発などでは役立ちます。

/**
 * DBの接続設定をしたPDOインスタンスを返却する
 * @return object
 */

PDOのエラーモードを設定する


ここはPDOを使用する場合は必ず書く、と覚えてください。
詳しく知りたい方は公式ドキュメントを参照してください。

実際に試してみる


同じ3-2フォルダにtest.phpを作成しましょう。
MySQLの操作は基本的に4種類です。

  • データの取得
  • データの追加
  • データの更新
  • データの削除

心配な方は再度MySQLを見返してみましょう。
それでは順番にやっていきましょう。

データを追加してみる


データを追加するSQL(MySQLはINSERTでしたね。)
下記をtest.phpにコピペしましょう。

<?php
// 作成したdb_connect.phpを読み込む
require_once('db_connect.php');

// 実行したいSQL文を準備
// 今回はusersテーブルにレコードを追加
$sql = "INSERT INTO users (name, password) VALUES ('Taro Yamada', 'taro')";
// 関数db_connect()からPDOを取得する
$pdo = db_connect();
try {
    $stmt = $pdo->prepare($sql);
    $stmt->execute();
    echo 'インサートしました。';
} catch (PDOException $e) {
    echo 'Error: ' . $e->getMessage();
    die();
}

これでhttp://localhost/LetsEngineer/curriculum/3-2/test.php
にアクセスしてください。
下記のように表示されたと思います。

ただ、実際に何が起こったのか、というとPHPのプログラムからMySQLにインサートをしました。
それではMAMP / XAMPPのMySQLにログインし、usersテーブルを確認してみてください。

require_once


これは外部ファイルを読み込む場合に使用します。
先ほど作成したdb_connect.phpでDBの設定を記載したので、それを読み込みます。

読み込むことで、db_connect.phpに記載した関数db_connect()が使用できます。
全て1つのファイルに記載しようとすると、下記のように長くなります。
長いよりは短い方が良いですよね?

<?php
// DB名
define('DB_DATABASE', 'yigroupBlog');
// MySQLのユーザー名
define('DB_USERNAME', 'root');
// MySQLのログインパスワード
define('DB_PASSWORD', 'root');
// DSN
define('PDO_DSN', 'mysql:host=localhost;charset=utf8;dbname='.DB_DATABASE);

/**
 * DBの接続設定をしたPDOインスタンスを返却する
 * @return object
 */
function db_connect() {
    try {
        // PDOインスタンスの作成
        $pdo = new PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD);
        // エラー処理方法の設定
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch(PDOException $e) {
        echo 'Error: ' . $e->getMessage();
        die();
    }
}

// 実行したいSQL文を準備
$sql = "INSERT INTO users (name, password) VALUES ('Taro Yamada', 'taro')";
// 関数db_connect()からPDOを取得する
$pdo = db_connect();
try {
    $stmt = $pdo->prepare($sql);
    $stmt->execute();
    echo 'インサートしました。';
} catch (PDOException $e) {
    echo 'Error: ' . $e->getMessage();
    die();
}

 

prepare、execute


PDOインスタンスはdb_connect()関数を呼ぶことで取得できます。
一旦取得したPDOを変数に入れておきましょう。
これで、PDOに関わる便利なメソッドを使用することができます。

キモになるのは下記の2つの文です。

$stmt = $pdo->prepare($sql);
$stmt->execute();

命令をMySQLにわかるかたちに準備するprepare

まず、prepareというPDOのメソッドを呼びます。
これは引数で渡された指示(SQL文)をMySQLに分かるかたちに変換します。
これを プリペアドステートメント と呼びます。
変換した文を一旦変数に格納します。

$stmt = $pdo->prepare($sql);

命令を実行するexecute

命令を実行するためにはexecuteを使用します。
execute(エクスキュート)は日本語としても認知があるかもしれません。

先ほど変数に入れたプリペアドステートメントもいろいろなメソッドを持っています。
その中の1つがexecuteです。

$stmt->execute();

これでMySQLに対して以下の命令(SQL)を実行したことになります。

INSERT INTO users (name, password) VALUES ('Taro Yamada', 'taro');

 

インサートする値を変更できるようにしたい


インサートする値を変更できるようにしたい場合は上の書き方に少し追記しなければなりません。
まずは例を見てみてください。

<?php
// 作成したdb_connect.phpを読み込む
require_once('db_connect.php');

$name = 'Jiro Yamada';
$password = 'jiro';

// 実行したいSQL文を準備
$sql = "INSERT INTO users (name, password) VALUES (:name, :password)";
// 関数db_connect()からPDOを取得する
$pdo = db_connect();
try {
    $stmt = $pdo->prepare($sql);
    $stmt->bindParam(':name', $name);
    $stmt->bindParam(':password', $password);
    $stmt->execute();
    echo 'インサートしました。';
} catch (PDOException $e) {
    echo 'Error: ' . $e->getMessage();
    die();
}

:name、:passwordでSQL内で変数が入る場所を指示する

name、password用の変数を用意し、この変数の値を変えれば、インサートされるデータが変わるようにしたいと思います。
まずははじめのSQL文の書き方が変わっていますね。

$sql = "INSERT INTO users (name, password) VALUES (:name, :password)";

:name:passwordはちょっと変数に似ています。
まだ何の値がはいるか分からないけど、とりあえず場所だけ確保しておく 、みたいな感じです。
確保する名前は識別できれば何でも良いです。
今回は変数名と同じ名前にしておきます。

それでは、この値はいつ入るのでしょうか?
次のbindParamで確定させていきます。

値をセットするbindParam

値をセットする前に、prepareプリペアドステートメント を作成しておきます。
このプリペアドステートメントを作成したタイミングで値をセットしていきます。
ちなみにここではセットではなく、 値をバインド(固定)する と言います。

$stmt = $pdo->prepare($sql);
// :nameに$nameの値をバインドする
$stmt->bindParam(':name', $name);
// :passwordに$passwordの値をバインドする
$stmt->bindParam(':password', $password);
$stmt->execute();

値をバインドすることで、SQL文として完成したものになるので、実行することができます。
変数の値を「Saburo Yamada」、「saburo」にして実行すれば、ちゃんとレコードが追加されています。

さて、このpreparebindParamexecuteはこの後何度も使用します。
3点セットで覚えるようにし、忘れたら都度見直しましょう。

データを取得してみる


それではDBからデータを取得してみましょう。
先ほどから使用している下記のSQL文を、PHPから命令できるようにしましょう。

SELECT * FROM users;

それではまず例です。

<?php
// 作成したdb_connect.phpを読み込む
require_once('db_connect.php');

// 実行したいSQL文を準備
$sql = "SELECT * FROM users";
// 関数db_connect()からPDOを取得する
$pdo = db_connect();
try {
    $stmt = $pdo->prepare($sql);
    $stmt->execute();

    // ループ文を使用して、1行ずつ読み込んで$rowに代入する
    // 読み込むものがなくなったらループ終了
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        echo $row['id'] . '、' . $row['name'] . '、' . $row['password'];
        echo '<br />';
    }
} catch (PDOException $e) {
    echo 'Error: ' . $e->getMessage();
    die();
}

実行結果は下図のようになりました。
人によって表示される内容は異なると思いますが、usersテーブルの全情報が表示されたのではないでしょうか?

SELECTした結果を取得

多くのコードは、先ほどやったINSERTのところで見たことがあると思います。
ただ、結果はどうやって取得するのでしょうか?

executeした後、$stmtには結果が格納されています。
この辺りはオブジェクトの概念的なものなので、とりあえずフローとして覚えましょう。

そして、後述するfetch$stmtから結果を取得します。

結果を1行ずつ読み込む

さて、結果を取得したはいいけど、このままでは使用することができません。
こういう場合、決まった書き方があるので、まずは1セットで覚えてしまいましょう。

// ループ文を使用して、1行ずつ読み込んで$rowに代入する
// 読み込むものがなくなったらループ終了
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {

    // 省略

この構文は複数の要素で成り立っています。
ひとつひとつ見ていきますが、SELECTした結果を表示する場合はこうする、と一旦は覚えてしまってください。

PDO::FETCH_ASSOC

実はDBから得た結果は、何も指示しなければぐちゃぐちゃな状態で持ってきます。
子供に「片付けろ」といったところで、いろんな場所に置いたり収納したりしてしまいますよね?
ちゃんとデータの返し方を指示してあげます。
返し方もいろいろな指定ができますが、今回は連想配列で返すよう指示する FETCH_ASSOC を使用します。
公式リファレンス-PDOStatement::fetch-

1行ずつ読み込むってどういうこと?

usersテーブルは下記のようになっています。

id name password
1 Taro Yamada taro
2 Jiro Yamada jiro
3 Saburo Yamada saburo

id = 1の行、id = 2の行…といったかたちで1行ずつ読み込んでいきます。
FETCH_ASSOCという指定をすることで、例えばid = 1の行は下記の連想配列で$rowに入ります。

$row = ["id" => 1, "name" => "Taro Yamada", "password" => "taro"];

これは配列、連想配列でやったものに似ていますね。
nameの値を取り出したければ、下記のように記載します。

echo $row["name"];

そして1週目のループが終わったら、次はid = 2の行が$rowに入ります。
2週目のループが終わったら、次はid = 3の行が$rowに入ります。
id = 4以降の行は存在しないので、そこでループ終了です。

下記のコードも上記を踏まえれば、理解しやすいのではないでしょうか?

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo $row['id'] . '、' . $row['name'] . '、' . $row['password'];
    echo '<br />';
}

条件文を動的に指定したい

id = 1のユーザーだけ欲しい、のように条件を変更して取得したいことは多々あると思います。
そんなときは、preparebindParamexecuteを使用します。

<?php
// 作成したdb_connect.phpを読み込む
require_once('db_connect.php');

// 変数を用意
$id = 1;

// 実行したいSQL文を準備(今回は指定したidの行を取得したい)
$sql = "SELECT * FROM users WHERE id = :id";
// 関数db_connect()からPDOを取得する
$pdo = db_connect();
try {
    $stmt = $pdo->prepare($sql);
    // :idに$idをバインドする
    $stmt->bindParam(':id', $id);
    $stmt->execute();

    // ループ文を使用して、1行ずつ読み込む
    // 読み込むものがなくなったらループ終了
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        echo $row['id'] . '、' . $row['name'] . '、' . $row['password'];
        echo '<br />';
    }
} catch (PDOException $e) {
    echo 'Error: ' . $e->getMessage();
    die();
}

基本的には今までやってきた考え方で分かるかと思います。
下記のSQLを発行したいのですが、IDの部分はケースバイケースで変えたいとします。

SELECT * FROM users WHERE id = :id;

その場合は後でbindParamを使って値をバインドするんでしたね。

$stmt->bindParam(':id', $id);

 

残りはほとんど同じです。
さて、残すところは更新と削除ですが、正直今までやったことで事足ります。

データを更新する


データを更新する場合は下記のようになります。

<?php
// 作成したdb_connect.phpを読み込む
require_once('db_connect.php');

// 変数を用意
$id = 1;
$name = 'Hanako Yamada';

// 実行したいSQL文を準備
$sql = "UPDATE users SET name = :name WHERE id = :id";
// 関数db_connect()からPDOを取得する
$pdo = db_connect();
try {
    $stmt = $pdo->prepare($sql);
    $stmt->bindParam(':name', $name);
    $stmt->bindParam(':id', $id);
    $stmt->execute();
    echo '更新完了です';
} catch (PDOException $e) {
    echo 'Error: ' . $e->getMessage();
    die();
}

今回は、 あるid の行の name を変更するプログラムです。

UPDATE users SET name = :name WHERE id = :id;

実行してみると、ちゃんと変更されているのが分かると思います。

データを削除してみる


最後は削除です。
あるid の行を削除したいとすると、下記のSQL文になります。

DELETE FROM users WHERE id = :id;

さて、どうなるでしょうか?
自分でちょっと考えてみてください。
回答はこの下です。

<?php
// 作成したdb_connect.phpを読み込む
require_once('db_connect.php');

// 変数を用意
$id = 1;

// 実行したいSQL文を準備
$sql = "DELETE FROM users WHERE id = :id";
// 関数db_connect()からPDOを取得する
$pdo = db_connect();
try {
    $stmt = $pdo->prepare($sql);
    $stmt->bindParam(':id', $id);
    $stmt->execute();
    echo '削除完了です';
} catch (PDOException $e) {
    echo 'Error: ' . $e->getMessage();
    die();
}

さいごに


長くなりましたが、以上で本項を終了します。
db_connect.phpはこの後のブログ作成で使用します。
ただ、test.phpの方は特に使用しないので、消してしまってもかまいません。

カテゴリー

アーカイブ

Close Bitnami banner
Bitnami