【PHP入門】MySQLに接続する最適な方法 PDOの使い方

PHPでMySQLに接続する方法

PHP から MySQL に接続する方法を解説します。

PDOmysqli どっちがいいの?とか、queryprepare どっちを使うべき?ということも、わかりやすく説明しちゃいます。

目次

PDO と mysqli どちらを使うべきか

PHP から MySQL に接続するためのAPIは PDOmysqli の2種類あります。

結論からいうと、これから PHP を始めるならば PDO を使いましょう。

PDOmysqli はどちらもほぼ同じことができます。主な違いは次のとおりです。

PDOmysqli
インターフェイスオブジェクト指向手続き型、オブジェクト指向
mysqlnd によるノンブロッキングな非同期クエリ非対応対応
クライアントサイドのプリペアドステートメント対応非対応
複数ステートメントほとんど対応対応
MySQL 5.1+ の全機能への対応ほとんど対応対応

PDO を使うメリット

  • 汎用性が高い。MySQL 以外にもいろいろなデータベースに対応しているので、これさえ覚えておけば他のデータベースにも対応できる。サポートされるデータベースはこちら
  • プリペアドステートメントが使えるので、SQLインジェクション対策がしやすい(あとでちゃんと説明します)。

mysqli を使うメリット

  • MySQL 専用のAPIなので、MySQL 独自の高度な機能にも対応している。
  • 手続き型で書くことができる。

というわけで、ほとんどの方は PDO を使ったほうがいいと思います。以降、PDO の使い方しか説明しません(強硬姿勢)。

PDO の使い方

接続、切断、エラー処理

MySQL に接続するためのコードをシンプルに書くと次のようになります。

//データベース接続情報
$dbuser = 'データベースユーザ名';
$dbpass = 'データベースパスワード';
$server = 'データベースサーバ名';
$db = 'データベース名';
$dsn = "mysql:host=$server;dbname=$db;";

try{
  //インスタンスの生成
  $dbh = new PDO($dsn, $dbuser, $dbpass);
  //接続を閉じる(省略可)
  $dbh = null;
//エラー処理
}catch (PDOException $e) {
  exit('データベース接続失敗: ' . $e->getMessage());
}

データベース接続情報

MySQL に接続するためのユーザ名、パスワード、サーバ名、データベース名を用意しておきます。そして、DSN(Data Source Name)を組み立てておきます。

インスタンスの生成

第一引数にDSN、第二引数にユーザ名、第三引数にパスワードを入れてインスタンスを生成します。

インスタンス(オブジェクト)名は $dbh としました。Database Handler の略だそうです。名前は何でもいいです。$pdo を使う人も多いですよね。

接続を閉じる

ここではとにかくシンプルなコードを書いているので、何もせずに接続を閉じます。

接続を閉じるには $dbhnull を代入します。

これをしなければ、スクリプトの終了時に自動的に接続が閉じられます。なので、省略してもいいのですが、ちゃんと書いたほうが律儀で真面目な感じがするので私は書く派です。

エラー処理

エラーが発生した場合の処理をするために、try-catch文を使っています。tryブロック内の処理を実行した結果、例外が投げられるとcatchブロックの処理が実行されます。

PDO はエラーが発生したときに例外( PDOException オブジェクト)を投げます。

エラー発生時に PDOException が投げられるのは PHP 8.0 からです。PHP 8 より前のバージョンを使っている場合は、エラーレポートモードの設定を変更する必要があります。「オプションを設定する」で解説しています。

SELECT する方法

では、SQL を実行してみましょう。queryメソッドを使う方法とprepareexecuteメソッドを使う方法があります。それぞれの使い方を解説した後に、どちらを使うべきか説明します。

query メソッド

//データベース接続情報
$dbuser = 'データベースユーザ名';
$dbpass = 'データベースパスワード';
$server = 'データベースサーバ名';
$db = 'データベース名';
$dsn = "mysql:host=$server;dbname=$db;";
$sql = 'SELECT * FROM `table_name`;';

try{
  //インスタンスの生成
  $dbh = new PDO($dsn, $dbuser, $dbpass);
  //SQLの実行
  $sth = $dbh->query($sql);
  //SQLの実行結果を格納
  $result = $sth->fetchAll(PDO::FETCH_ASSOC);
  //接続を閉じる(省略可)
  $dbh = null;
  //SQLの実行結果の表示
  echo '<pre>';
  print_r($result);
  echo '</pre>';
//エラー処理
}catch (PDOException $e) {
  exit('データベース接続失敗: ' . $e->getMessage());
}
SQLの実行

queryメソッドにSQL文を渡して実行します。

オブジェクト名は $sth にしました。Statement Handler の略です。好きな名前をつけてください。

SQLの実行結果を格納

fetchAll メソッドでSQLの実行結果を取得して $result に格納します。fetchAll はSQLの実行結果のすべてを配列で返します。

fetchAll の代わりに fetch メソッドを使うこともできます。fetch はSQLの実行結果を1行だけ返します。

フェッチモードの設定

fetch, fetchAll の引数として PDO::FETCH_ASSOC を渡しています。これによって返す結果の形式を制御しています。

設定するモードによってprint_r($result)の出力は次のように変わります。

//PDO::FETCH_ASSOCの場合
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => まさお
            [age] => 33
            [created] => 2022-12-06 20:17:13
        )
    [1] => Array
        (
            [id] => 2
            [name] => まさこ
            [age] => 28
            [created] => 2022-12-06 20:17:25
        )
)

//PDO::FETCH_BOTH (デフォルト)の場合
Array
(
    [0] => Array
        (
            [id] => 1
            [0] => 1
            [name] => まさお
            [1] => まさお
            [age] => 33
            [2] => 33
            [created] => 2022-12-06 20:17:13
            [3] => 2022-12-06 20:17:13
        )
    [1] => Array
        (
            [id] => 2
            [0] => 2
            [name] => まさこ
            [1] => まさこ
            [age] => 28
            [2] => 28
            [created] => 2022-12-06 20:17:25
            [3] => 2022-12-06 20:17:25
        )
)

//PDO::FETCH_NUMの場合
Array
(
    [0] => Array
        (
            [0] => 1
            [1] => まさお
            [2] => 33
            [3] => 2022-12-06 20:17:13
        )
    [1] => Array
        (
            [0] => 2
            [1] => まさこ
            [2] => 28
            [3] => 2022-12-06 20:17:25
        )
)

prepare、execute メソッド

//データベース接続情報
$dbuser = 'データベースユーザ名';
$dbpass = 'データベースパスワード';
$server = 'データベースサーバ名';
$db = 'データベース名';
$dsn = "mysql:host=$server;dbname=$db;";
$sql = 'SELECT * FROM `table_name` WHERE `name` = :name AND `age` = :age;';
$name = 'まさお';
$age = 32;

try{
  //インスタンスの生成
  $dbh = new PDO($dsn, $dbuser, $dbpass);
  //SQLの準備
  $sth = $dbh->prepare($sql);
  //値をバインドする
  $sth->bindValue(':name', $name);
  $sth->bindValue(':age', $age, PDO::PARAM_INT);
  //SQLの実行
  $sth->execute();
  //SQLの実行結果を格納
  $result = $sth->fetchAll(PDO::FETCH_ASSOC);
  //接続を閉じる(省略可)
  $dbh = null;
  //SQLの実行結果の表示
  echo '<pre>';
  print_r($result);
  echo '</pre>';
//エラー処理
}catch (PDOException $e) {
  exit('データベース接続失敗: ' . $e->getMessage());
}
SQLの準備

prepareメソッドを使って、SQL を実行する準備をします。この段階ではまだ実行されません。

prepareに渡された変数$sqlの内容を見てみると、コロンで始まる文字列 :name:age が確認できます。これらはプレースホルダと呼ばれるもので、この後に正式な値にバインドされます。バインドとは結びつけるとか関連付けるという意味です。

値をバインドする

bindValueメソッドで、:name$name:age$ageを結びつけています。

第三引数でデータ型を指定します。指定しない場合の初期値はPDO::PARAM_STRです。

  • PDO::PARAM_STR: 文字列
  • PDO::PARAM_INT: 数値
  • PDO::PARAM_BOOL: ブール値
  • PDO::PARAM_NULL: NULL
SQL の実行

executeメソッドで、SQLを実行します。

query と prepare どちらを使うべきか

query がたった1行でSQLを実行しているのに対して、prepare + execute は「準備→バインド→実行」の3段階になっていて面倒くさそうです。

しかし、面倒くさいのには理由がありまして。prepare + execute を使うということはプリペアドステートメントを使うということなんです。プリペアドステートメントを使うメリットは次のとおりです。

  • 同じSQL文を値を変えて使い回すことができる。
  • SQLインジェクション対策になる。

特に2つめのSQLインジェクション対策が大事です。SQLインジェクションとは想定外のSQL文を実行させることによって、データベースを不正に操作する攻撃方法のことです。外部から受け取った値がSQL文に含まれる場合に、SQLインジェクションが発生する可能性があります。

なので、外部から受け取る値がSQL文に含まれない場合は query、含まれる場合は prepare + execute を使うという使い分けをしましょう。それが面倒ならば全部 prepare + execute でやればいいと思います。全部 query でやるのはダメ。ゼッタイ。

以降、prepare+executeでやる方法しか説明しません(強硬姿勢)。

INSERT する方法

//データベース接続情報
$sql = 'INSERT INTO `table_name` (`name`, `age`, `created`) VALUES(:name, :age, NOW());';
$name = 'ひろみ';
$age = 98;

//SQLの準備
$sth = $dbh->prepare($sql);
//値をバインドする
$sth->bindValue(':name', $name);
$sth->bindValue(':age', $age, PDO::PARAM_INT);
//SQLの実行
$sth->execute();
//INSERTしたidを取得
$id = $dbh->lastInsertId();
//INSERTしたレコード数を取得
$count = $sth->rowCount();
//接続を閉じる(省略可)
$dbh = null;

「準備→バインド→実行」の3段階です。SELECT と同じですね。

INSERT した id を取得

INSERTしたレコードのidを取得したいときはlastInsertIdメソッドを使います。$sthではなく$dbhから取得するので注意してください。

lastInsertIdを使うにはAUTO_INCREMENTが設定されたPRIMARY KEYのカラムが存在する必要があります。カラム名はidだったりすることが多いですが、何でもOKです。

INSERT したレコード数を取得

挿入したレコード数を取得するにはrowCountメソッドを使います。

UPDATE する方法

//データベース接続情報
$sql = 'UPDATE `table_name` SET `age` = :age WHERE `name` = :name;';
$name = 'まさお';
$age = 33;

//SQLの準備
$sth = $dbh->prepare($sql);
//値をバインドする
$sth->bindValue(':name', $name);
$sth->bindValue(':age', $age, PDO::PARAM_INT);
//SQLの実行
$sth->execute();
//UPDATEしたレコード数を取得
$count = $sth->rowCount();
//接続を閉じる(省略可)
$dbh = null;

UPDATE したレコード数を取得

変更したレコード数を取得するにはrowCountメソッドを使います。

DELETE する方法

//データベース接続情報
$sql = 'DELETE FROM `table_name` WHERE `id` = :id;';
$id = 4;

//SQLの準備
$sth = $dbh->prepare($sql);
//値をバインドする
$sth->bindValue(':id', $id, PDO::PARAM_INT);
//SQLの実行
$sth->execute();
//DELETEしたレコード数を取得
$count = $sth->rowCount();
//接続を閉じる(省略可)
$dbh = null;

DELETE したレコード数を取得

削除したレコード数を取得するにはrowCountメソッドを使います。

オプションを設定する

データベースハンドル$dbhの属性を設定することによってPDOの挙動を制御することができます。方法は2つ、インスタンスの生成時に設定する方法と、インスタンスの生成後にsetAttributeメソッドで設定する方法です。

インスタンス生成時に設定する方法

//データベース接続情報
$dbuser = 'データベースユーザ名';
$dbpass = 'データベースパスワード';
$server = 'データベースサーバ名';
$db = 'データベース名';
$dsn = "mysql:host=$server;dbname=$db;";
$options = array(
  属性 => 値,
  属性 => 値
);

//インスタンスの生成
$dbh = new PDO($dsn, $dbuser, $dbpass, $options);

インスタンスを生成するときの第四引数にオプションを連想配列で渡します。

利用できるオプションは下記で確認してください。

setAttribute で設定する方法

//データベース接続情報
$dbuser = 'データベースユーザ名';
$dbpass = 'データベースパスワード';
$server = 'データベースサーバ名';
$db = 'データベース名';
$dsn = "mysql:host=$server;dbname=$db;";

//インスタンスの生成
$dbh = new PDO($dsn, $dbuser, $dbpass);
//オプションの設定
$dbh->setAttribute(属性, 値);
$dbh->setAttribute(属性, 値);

設定例

//エラーが発生したときに例外を投げるようにする
//PHP7以下の場合に設定する必要があります。PHP8以上では不要です。
$options = array(
  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);

//フェッチモードを設定する
//fetch, fetchAllの引数で設定することもできます
$options = array(
  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);

まとめ

以上を踏まえたPDO_MySQLの使い方テンプレートがこちらです。

//データベース接続情報
$dbuser = 'データベースユーザ名';
$dbpass = 'データベースパスワード';
$server = 'データベースサーバ名';
$db = 'データベース名';
$dsn = "mysql:host=$server;dbname=$db;";
$sql = 'SELECT * FROM `table_name` WHERE `id` = :id AND `name` = :name;';
$options = array(
  属性 => 値,
  属性 => 値
);

try {
  //インスタンスの生成
  $dbh = new PDO($dsn, $dbuser, $dbpass, $options);
  //SQLの準備
  $sth = $dbh->prepare($sql);
  //値をバインドする
  $sth->bindValue(':id', 1, PDO::PARAM_INT);
  $sth->bindValue(':name', 'まさお', PDO::PARAM_STR);
  //SQLの実行
  $sth->execute();
  //SQLの実行結果を格納
  $result = $sth->fetchAll(PDO::FETCH_ASSOC);
  //INSERTしたidを取得
  $id = $dbh->lastInsertId();
  //レコード数を取得
  $count = $sth->rowCount();
  //接続を閉じる(省略可)
  $dbh = null;
  //エラー処理
} catch (PDOException $e) {
  exit('データベース接続失敗: ' . $e->getMessage());
}

でわでわ

PHPでMySQLに接続する方法

この記事が気に入ったら
いいね または フォローしてね!

シェアしてね

コメント

コメントする

目次