PHP から MySQL に接続する方法を解説します。
PDO と mysqli どっちがいいの?とか、query と prepare どっちを使うべき?ということも、わかりやすく説明しちゃいます。
PDO と mysqli どちらを使うべきか
PHP から MySQL に接続するためのAPIは PDO と mysqli の2種類あります。
結論からいうと、これから PHP を始めるならば PDO を使いましょう。
PDO と mysqli はどちらもほぼ同じことができます。主な違いは次のとおりです。
| PDO | mysqli | |
|---|---|---|
| インターフェイス | オブジェクト指向 | 手続き型、オブジェクト指向 |
| mysqlnd によるノンブロッキングな非同期クエリ | 非対応 | 対応 |
| クライアントサイドのプリペアドステートメント | 対応 | 非対応 |
| 複数ステートメント | ほとんど対応 | 対応 |
| MySQL 5.1+ の全機能への対応 | ほとんど対応 | 対応 |
PDO を使うメリット
- 汎用性が高い。MySQL 以外にもいろいろなデータベースに対応しているので、これさえ覚えておけば他のデータベースにも対応できる。サポートされるデータベースはこちら。
- プリペアドステートメントが使えるので、SQLインジェクション対策がしやすい(あとでちゃんと説明します)。
mysqli を使うメリット
- MySQL 専用のAPIなので、MySQL 独自の高度な機能にも対応している。
- 手続き型で書くことができる。
というわけで、ほとんどの方は PDO を使ったほうがいいと思います。以降、PDO の使い方しか説明しません(強硬姿勢)。
無料で利用できるプログラミング学習サービスをお探しならば Code Lesson はいかがでしょうか。プロのエンジニアが監修した学習ロードマップで効率的に学習、AIに質問、最後にクイズで理解度をチェックできます。
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 を使う人も多いですよね。
接続を閉じる
ここではとにかくシンプルなコードを書いているので、何もせずに接続を閉じます。
接続を閉じるには $dbh に null を代入します。
これをしなければ、スクリプトの終了時に自動的に接続が閉じられます。なので、省略してもいいのですが、ちゃんと書いたほうが律儀で真面目な感じがするので私は書く派です。
エラー処理
エラーが発生した場合の処理をするために、try-catch文を使っています。tryブロック内の処理を実行した結果、例外が投げられるとcatchブロックの処理が実行されます。
PDO はエラーが発生したときに例外( PDOException オブジェクト)を投げます。
SELECT する方法
では、SQL を実行してみましょう。queryメソッドを使う方法とprepare、executeメソッドを使う方法があります。それぞれの使い方を解説した後に、どちらを使うべきか説明します。
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());
}でわでわ
無料で利用できるプログラミング学習サービスをお探しならば Code Lesson はいかがでしょうか。プロのエンジニアが監修した学習ロードマップで効率的に学習、AIに質問、最後にクイズで理解度をチェックできます。

コメント