こんにちは、かつコーチです。
前回まででトレイトを扱い、PHPのオブジェクト指向まわりは一通り触れてきました。
今回からは新しいテーマ、「データベース」に入っていきます。
PHPだけでどれだけ動的なページを作れても、会員情報や投稿内容を保存する場所がなければ、実用的なWebアプリケーションにはなりません。
その保存場所として今回使うのがMySQLというデータベースで、PHPからMySQLに接続するための仕組みがPDO(PHP Data Objects)です。
この記事では、XAMPPで用意したMySQLにPHPから接続するところまでを、一緒に進めていきます。
PDOとは?
データベース接続のための共通インターフェース
PDOは、PHPからさまざまな種類のデータベース(MySQL、PostgreSQL、SQLiteなど)に接続するための共通の窓口です。
PHPには以前、MySQL専用のmysql_connectやmysqli_connectという関数もありました。
ただしmysql_系の関数はすでに廃止されており、mysqli_はMySQL専用でほかのデータベースには使えません。
その点PDOは、接続文字列(DSN)を変えるだけで別のデータベースにも対応できる汎用性を持っています。
なぜPDOを使うのか
PDOをおすすめする理由は主に3つあります。
- 複数のデータベースに対応できる(学んだ知識を使い回しやすい)
- 次の記事で扱うプリペアドステートメントが標準で使え、SQLインジェクション対策がしやすい
- 例外処理(
try-catch)でエラーをきれいに扱える
実はLaravelの中で使われているEloquent(データベース操作をラクにしてくれる仕組み)も、内部的にはPDOを土台にしています。
つまりPDOの基本を理解しておくことは、この先Laravelを学ぶときの土台づくりにもなります。
MySQLに接続するための準備
phpMyAdminでデータベースとテーブルを作る
XAMPP Control PanelでApacheとMySQLがどちらも起動している状態(緑色)を確認してください。
まだの場合は、02回目の記事を参考に両方とも起動しておきましょう。
ブラウザでhttp://localhost/phpmyadminにアクセスすると、phpMyAdminという管理画面が開きます。
ここから「新規作成」を選び、sample_dbという名前のデータベースを作成します。
作成したデータベースを選んだ状態で「SQL」タブを開き、以下のSQLを実行してテーブルを作ります。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (name, email) VALUES
('田中太郎', 'tanaka@example.com'),
('佐藤花子', 'sato@example.com');
このテーブルを、これから何回かの記事にわたって使い回していきます。
PDOで接続する
基本の接続コード
準備ができたら、PHPからPDOで接続してみましょう。
<?php
$dsn = 'mysql:host=localhost;dbname=sample_db;charset=utf8mb4';
$user = 'root';
$password = '';
try {
$pdo = new PDO($dsn, $user, $password);
echo "接続に成功しました";
} catch (PDOException $e) {
echo "接続に失敗しました: " . $e->getMessage();
}
?>
$dsn(データソースネーム)には、接続先のデータベースの種類・ホスト名・データベース名・文字コードをまとめて指定します。
XAMPPのMySQLは初期状態でユーザー名がroot、パスワードが空文字なので、学習用途ではそのまま使って問題ありません。
new PDO(...)の部分が実際に接続を試みる処理で、失敗するとPDOExceptionという例外が発生します。
try-catchで接続エラーを扱う理由
接続処理を必ずtry-catchで囲むのには理由があります。
データベースサーバーが落ちていたり、パスワードが間違っていたりすると、接続時に必ずエラーが起きます。
try-catchで囲んでおかないと、PHPが生のエラーメッセージ(データベースのホスト名やパスワードのヒントが含まれることもあります)をそのまま画面に表示してしまい、セキュリティ上も好ましくありません。
catchブロックで受け取った$e->getMessage()を、開発中はそのまま表示してデバッグに使い、本番環境ではログに記録するだけにする、という使い分けが一般的です。
つまずきやすいポイント
①文字コード指定を忘れて日本語が文字化けする
私が最初にPDOでMySQLに接続したとき、DSNにcharset=utf8mb4を書かずに接続していました。
<?php
// ❌ Before:charset未指定
$dsn = 'mysql:host=localhost;dbname=sample_db';
$pdo = new PDO($dsn, 'root', '');
?>
このコードでも接続自体はできてしまうのですが、日本語のデータを取得すると「田中太郎」が「??????」のような文字化けになって表示され、原因が分からず1時間近く悩みました。
原因は、PHPとMySQLの間でやり取りする文字コードが一致していなかったことでした。
<?php
// ✅ After:DSNにcharsetを明示する
$dsn = 'mysql:host=localhost;dbname=sample_db;charset=utf8mb4';
$pdo = new PDO($dsn, 'root', '');
?>
DSNにcharset=utf8mb4を明示するだけで文字化けは解消しました。
日本語を扱うプロジェクトでは、DSNの文字コード指定を忘れないようにしましょう。
②データベース名を間違えて「Unknown database」エラーになる
もう一つよくあるのが、データベース名のタイプミスです。
SQLSTATE[HY000] [1049] Unknown database 'sampledb'
このエラーは、phpMyAdminで作成したsample_dbと、コード内のdbnameの綴りが一致していないときに出ます。
アンダースコアの有無や大文字小文字の違いなど、細かいところで発生しやすいので、エラーが出たらまずphpMyAdminの画面と見比べる癖をつけると早く解決できます。
応用:接続オプションでエラーモードを設定する
PDOのエラーモードを明示的に設定する
PDOには、エラーが起きたときの挙動を細かく制御するオプションがあります。
<?php
$dsn = 'mysql:host=localhost;dbname=sample_db;charset=utf8mb4';
try {
$pdo = new PDO($dsn, 'root', '', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
} catch (PDOException $e) {
exit("接続エラー: " . $e->getMessage());
}
?>
PDO::ATTR_ERRMODEをPDO::ERRMODE_EXCEPTIONに設定しておくと、接続後のSQL実行エラーもすべて例外として捕まえられるようになります。
これを設定しておかないと、SQLの実行エラーが静かに無視されて「なぜかデータが取れない」という気づきにくいバグにつながることがあるため、最初の接続時点で設定しておくのがおすすめです。
PDO::ATTR_DEFAULT_FETCH_MODEは、次の記事で扱うデータ取得時の形式をあらかじめ指定しておくオプションです。
まとめ
この記事のポイント
- PDOはPHPからさまざまなデータベースに接続するための共通インターフェース
- 接続にはDSN(データベースの種類・ホスト名・DB名・文字コード)とユーザー名・パスワードが必要
- 接続処理は必ず
try-catchで囲み、PDOExceptionを捕まえる - DSNに
charset=utf8mb4を指定しないと日本語が文字化けすることがある PDO::ATTR_ERRMODEを設定しておくと、この後のSQL実行エラーも例外で拾えるようになる
次に読むべき記事
接続ができるようになったら、次はいよいよデータベースからデータを取り出してみましょう。
→ 次の記事:PDOでSQLを実行してデータを取得する方法