PHP入門 データベースへの接続

PHPからデータベースに接続する方法を解説しています。

データベース接続

PHPアプリからデータベースを操作するには、まずデータベースに対して接続を確立する必要があります。

<?php
$dsn = 'mysql:dbname=test; host=127.0.0.1; charset=utf8';
$usr = 'root';
$passwd = 'test';

try{

    $db = new PDO($dsn, $usr, $passwd);
    print '接続に成功しました';

}catch (PDOException $e){
    die("接続エラー:{$e->getMessage()}");
}finally {
    $db = null;
}
実行結果
実行結果

接続と切断

データベースへの接続を管理するのは、PDOクラスの役割です。まず、PDOクラスをインスタンス化します。接続を切断するには、オブジェクト変数$dbにnullをセットします。ただし、データベースへの接続はスクリプトの終了時に自動的に切断されます。

構文:PDOクラス

new PDO(string $dsn [, string $username [, string $passwd [, array $options]]])
$dsnデータベース接続文字列
$username接続ユーザー名
$passwd接続時のパスワード
$options接続オプション

データベース接続文字列は、データベースに接続するための情報(ホスト名やポート番号、データベース名など)を一定の書式でまとめたものです。データベース接続文字列の書式は、接続先のデータベースによって異なります。

データベース接続文字列の書式

接続先のデータベース接続文字列
MySQL/MariaDBmysql:host=127.0.0.1;port=3307;dbname=testdb
mysql:unix_socket=/tmp/mysql.sock;dbname=testdb(Unixソケット)
PostgreSQLpgsql:host=127.0.0.1;port=5432;dbname=testdb;user=root;password=test
SQLitesqlite:test.sqlite(ファイルシステム上のデータベース)
sqlite::memory:(メモリ上のデータベース)
Oracleoci:dbname=testdb(tnsnames.ora使用時)
oci:dbname=//127.0.0.1:1521/testdb(instantclient使用時)
SQL Servermssql:host=127.0.0.1;dbname=testdb
ODBCodbc:testdb(ドライバーマネージャー)
odbc:Driver={Microsoft Access Driver(*.mdb)};Dbq=C:\\testdb.mdb;Uid=Admin

例外処理の基本(try~catch~finally命令)

データベースへの接続ができなかった場合は、PDOException例外を発生します。例外とは、アプリの実行時に発生する異常な状態のことです。例外処理とは、あらかじめ発生するかもしれないエラーを想定しておき、そのエラーが発生した場合に行うべき処理のことです。例外を表現するにはtry~catch~finally命令を利用します。

構文:try~catch~finally命令

try{
     //例外が発生する可能性があるコード
} catch( 発生するかもしれない例外の種類 例外を受け取る変数名 ){
     //例外発生時の処理
}finally{
     //例外の有無にかかわらず実行されるコード
}

try~catch~finally命令を利用していない場合、データベースへの接続が失敗するとスクリプトが終了してしまいます。tryブロックでコードをくくった場合には、例外が発生しても、処理はそのままcatchブロックに引き継がれ処理が継続します。最後のfinallyブロックは、例外があったかどうかにかかわらず、最終的に必ず実行されるブロックです。tryブロックの中で利用したリソースの後始末などのために利用します。例えば、データベースの切断など記述します。

finallyブロックは、tryブロックでreturn命令が呼びされた場合にも実行されます。その際、finallyブロックでもreturn命令が書かれていた場合は、戻り値がそのものが上書きされてしまうので、finallyブロックにreturn命令は記述しません。

例外クラスで呼び出せるメソッド

メソッド概要
getMessage()例外メッセージ
getCode()例外コード
getFile()例外が発生したファイル名
getLine()例外発生した行数
getPrevious()前の例外
getTrace()バックトレース(配列)
getTraceAsString()バックトレース(文字列)
どのような例外が発生するかは使用しているメソッド/関数によるのでPHPマニュアルから個別のメソッドの説明を開き調べます。

接続スクリプトの外部化

データベースへの接続は定型的で、データベース接続文字列やユーザー名、パスワードのような環境依存の情報が複数個所に分散しているのは、よくないためユーザー定義関数として外部化します。

DbManager.php

<?php
function getDb() :PDO{
    $dsn = 'mysql:dbname=testdb; host=127.0.0.1; charset=utf8;';
    $usr = 'testusr';
    $passwd = 'testpw';

    //データベースへの接続を確立
    $db = new PDO($dsn, $usr, $passwd);
    return $db;
}

定義したgetDb関数を呼び出す方法

<?php
require_once './DbManager.php';
$db = getDb();

接続オプション

データベース接続時の挙動を決めるパラメーター情報のことを接続オプションと言います。接続オプションは、PDOクラスをインスタンス化する場合に連想配列「オプション名 => 設定値」の形式で指定するか、setAttributeメソッドを使って個別に設定できます。

構文:setAttributeメソッド

PDO::setAttribute(int $attribute, mixed $value):bool
$attributeオプション名
$value設定値

利用可能な接続パラメーター

定数概要設定値/戻り値
PDO::ATTR_AUTOCOMMIT自動コミットを有効化するか(true/false)true
PDO::ATTR_TIMEOUTデータベースとの通信におけるタイムアウト時間
PDO::ATTR_CASE取得したフィールド名の変換方法PDO::CASE_NATURAL
設定値概要
PDO::CASE_LOWER小文字に変換
PDO::CASE_NATURAL変換しない
PDO::CASE_UPPER大文字に変換
PDO::ATTR_ERRMODEエラーの通知方法PDO::ERRMODE_EXCEPTION
設定値概要
PDO::ERRMODE_SILENTエラーコードのみ設定
PDO::ERRMODE_WARNING警告を発生
PDO::ERRMODE_EXCEPTION例外を発生
PDO::ATTR_ORACLE_NULLS空文字列⇔null値を変換するか(Oracleだけでなく、全ドライバーで利用可)PDO::NULL_NATURAL
設定値概要
PDO::NULL_NATURAL変換しない
PDO::NULL_EMPTY_STRING空文字→nullに変換
PDO::NULL_TO_STRINGnull→空文字に変換
PDO::ATTR_PRERSISTENT接続的接続を有効にするか(true/false)false
PDO::ATTR_DRIVER_NAMEドライバー名mysql
PDO::ATTR_CONNECTION_STATUSサーバーへの接続状態127.0.0.1 via TCP/IP
PDO::ATTR_SERVER_INFOサーバー状態Uptime:2293 Threads:7
Questions:6 Slow Queries:0
Opens: 16 Flush tables:1
Open tables: 10 Queries per
second avg:0.002
PDO::ATTR_SERVER_VERSIONサーバーのバージョン5.5.5-10.4.17-MariaDB
PDO::ATTR_CLIENT_VERSIONクライアントのバージョンmysqlnd 8.0.0

1、PDO::ATTR_ERRMODE

接続中にエラーが発生した場合、これをどのように通知するか決めます。PDO::ATTR_ERRMODEパラメーターにPDO::ERRMODE_SILENTを指定した場合、PHPはエラーが発生した場合にもエラーコードを設定するだけでエラー出力しません。もし、この設定で発生したエラー確認したい場合には、PDO::errorCode、errorInfoメソッドを使用してください。errorInfoメソッドは、次に示すエラー情報を配列として返します。

errorInfメソッドに含まれるエラー情報

インデックス概要
0共通のエラーコード
1ドライバー固有のエラーコード
2ドライバー固有のエラーメッセージ

errorInfoメソッドに含まれる共通エラーコードは、errorCodeメソッドによって返される値と等価です。

<?php
require_once './DbManager.php';
$db = getDb();
$db -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec('MECHA KUCHA');
if($db->errorCode() !== '00000'){   //➊
    $info = $db->errorInfo();
    print "エラーコード:{$info[0]}<br />";
    print "エラー(ドライバー):{$info[1]}<br />";
    print "エラーメッセージ:{$info[2]}<br />";
}
実行結果
実行結果

execメソッドは、データベースに対して問い合わせ(クエリ)命令を発行するためのメソッドです。SQL命令に対する値のバインド(代入)が不要で、かつ、結果を必要としないクエリを発行する場合には、execメソッドを利用します。

構文:execメソッド

PDO::exec(string $statement): int
$statement任意のクエリ

PDO::ATTR_ERRMODEの既定値は、PHP7まではPDO::ERRMODE_SILENT、PHP8以降はPDO::ERRMODE_EXCEPTIONです。バージョンにかかわらず、クエリによって発生したエラーをtry~catch命令で処理するためには、明示的にPDO::ERRMODE_EXCEPTIONを設定します。

DbManager.php

<?php
function getDb() :PDO{
    $dsn = 'mysql:dbname=testdb; host=127.0.0.1; charset=utf8;';
    $usr = 'testusr';
    $passwd = 'testpw';

    //データベースへの接続を確立
    $db = new PDO($dsn, $usr, $passwd);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $db;
}

これによって、クエリ実行のつど(❶)のコードを記述する必要がなくなります。

<?php
require_once './DbManager.php';

try{
$db = getDb();
$db -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->exec('MECHA KUCHA');
} catch(PD){
if($db->errorCode() !== '00000'){
    print "エラーコード:{$info[0]}<br />";
    print "エラーメッセージ:{$info[2]}<br />";
}
実行結果
実行結果

2、PDO::ATTR_CASE

データベースサーバーによって、取得したテーブルのフィールド名をそのまま返さず、自動的に大文字(小文字)に変換するものがあります。そのような場合、PDO::ATTR_CASEパラメーターを設定しておくことで、こうしたデータベースごとの違いを吸収できます。

<?php
require_once './DbManager.php';

$db = getDb();
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
print_r($db->query('SELECT * FROM book') -> fetchAll(PDO::FETCH_ASSOC));
//結果:Array([0]=>Array([ISBN]=> ・・・・・[TITLE] => ・・・・))

PDO::ATTR_CASEパラメーターをPDO::CASE_UPPER(大文字に変換)としているので、フィールド名がすべて大文字で得られることが確認できます。

3、PDO::ATTR_PERSISTENT

PDO::ATTR_PERSISTENTパラメーターを有効にすると、持続的接続が有効になります。持続的接続とは、スクリプトが終了しても破棄せずに維持され、他から要求があった場合にこれを再利用する接続のことを言います。持続的接続によって、接続確率のためのオーバーヘッドを軽減できるので、特にアクセス数が多いサイトではパフォーマンス改善になります。

$db = new PDO($dsn, $usr, $passwd, [PDO::ATTR_PERSISTENT => true]);