【PHP】PHPからMySQLに接続する:PDOの基本

phpアイキャッチ PHP

こんにちは、かつコーチです。

前回まででトレイトを扱い、PHPのオブジェクト指向まわりは一通り触れてきました。

今回からは新しいテーマ、「データベース」に入っていきます。

PHPだけでどれだけ動的なページを作れても、会員情報や投稿内容を保存する場所がなければ、実用的なWebアプリケーションにはなりません。

その保存場所として今回使うのがMySQLというデータベースで、PHPからMySQLに接続するための仕組みがPDO(PHP Data Objects)です。

この記事では、XAMPPで用意したMySQLにPHPから接続するところまでを、一緒に進めていきます。

PDOとは?

データベース接続のための共通インターフェース

PDOは、PHPからさまざまな種類のデータベース(MySQL、PostgreSQL、SQLiteなど)に接続するための共通の窓口です。

PHPには以前、MySQL専用のmysql_connectmysqli_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_ERRMODEPDO::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を実行してデータを取得する方法

タイトルとURLをコピーしました