PHP-DB - 10. PDO例外
続いて PDO
ライブラリの例外クラスである PDOException
クラスについて学習します。PDOライブラリとのやりとりの中で、予期せぬ事態が起こりうる可能性があります。たとえば接続先のデータベースがダウンしていたり、データベースの認証に失敗したりするケースです。他にも実行するSQLの構文に誤りが存在する、というケースも考えられるでしょう。 PDO
ライブラリは このような予期せぬ事態に対して PDOException
をスローできます。
SQL構文の不具合
ここではまずSQL構文に誤りがある場合の PDO
ライブラリの挙動について確認しておきましょう。簡単なSQLを実行する次のプログラム( pdo8.php
)を作成します。
<?php
$dsn = "mysql:host=localhost;dbname=eldb;charset=utf8mb4";
$username = "root";
$password = "admin";
$pdo = new PDO($dsn, $username, $password);
$sql = "select id, title from categories";
// $sql = "select id, title from categorie";
$st = $pdo->query($sql);
var_dump($st);
// $row = $st->fetch();
// var_dump($row);
このプログラムではいくつかのコードをコメントアウトしています。のちほど、これらのコメントアウトを解除(コメントイン)することで、実行結果にどのような変化が起こるかを確認します。
このプログラムでは select
文を定義して $pdo->query($sql)
を実行し、戻り値である PDOStatement
インスタンスを var_dump
関数で出力しています。現時点のプログラムには特に誤りはないので、データベースに正常に接続できた場合は、次のような実行結果が表示されるでしょう。
$ php pdo8.php
object(PDOStatement)#2 (1) {
["queryString"]=>
string(32) "select id, title from categories"
}
実行結果から var_dump
関数によって PDOStatement
インスタンスが表示されているのがわかります。
次にコメントアウトしている部分を解除して、次のようにプログラム( pdo8.php
)のSQLを修正します。
<?php
$dsn = "mysql:host=localhost;dbname=eldb;charset=utf8mb4";
$username = "root";
$password = "admin";
$pdo = new PDO($dsn, $username, $password);
// $sql = "select id, title from categories";
$sql = "select id, title from categorie";
$st = $pdo->query($sql);
var_dump($st);
// $row = $st->fetch();
// var_dump($row);
ここでは select
文に指定しているテーブル名( categorie
)にタイプミスがあります。 PDO
インスタンスの query
メソッドは不正なSQLを受け取ると戻り値に論理値の false
を返します。
このようなケースでプログラムを実行すると次のような結果が表示されるでしょう。
$ php pdo8.php
bool(false)
実行結果から $pdo->query($sql)
呼び出しの結果、 PDOStatement
インスタンスではなく論理値の false
が返却されていることがわかります。
このような戻り値の変化は気づきにくく、プログラムの不具合の原因になりやすいものです。そこでPDOライブラリは例外( PDOException
)をスローするように変更できます。
PDOのエラーレポート設定
PDO
インスタンスの PDO::ATTR_ERRMODE
属性を指定することで、さきほどのような異常時の振る舞いを変更できます。
エラーレポート設定 | エラー時の動作 |
---|---|
PDO::ERRMODE_SILENT |
エラーコードのみ設定する(デフォルト) |
PDO::ERRMODE_WARNING |
E_WARNINGを発生させる |
PDO::ERRMODE_EXCEPTION |
例外を投げる |
デフォルトの
PDO::ERRMODE_SILENT
の場合、PDO
インスタンスのerrorCode
メソッドやerrorInfo
メソッドによってエラーコードを取得できます。
ここでは PDO
クラスの setAttribute
メソッドを使って、 PDO::ATTR_ERRMODE
属性に PDO::ERRMODE_EXCEPTION
を指定することで、異常時に例外( PDOException
)をスローするように変更してみましょう。さきほどのプログラム( pdo8.php
)を次のように実装します。
<?php
$dsn = "mysql:host=localhost;dbname=eldb;charset=utf8mb4";
$username = "root";
$password = "admin";
$pdo = new PDO($dsn, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// $sql = "select id, title from categories";
$sql = "select id, title from categorie";
$st = $pdo->query($sql);
var_dump($st);
上記にようにエラーレポート設定を変更しておくことで、 $pdo->query($sql)
呼び出し時に例外( PDOException
)をスローできます。それではプログラムを実行してみましょう。
$ php pdo8.php
Fatal error: Uncaught PDOException: SQLSTATE[HY000]:
General error: 1 no such table: categorie in
/home/ec2-user/environment-db/pdo8_3.php:10
Stack trace:
#0 /home/ec2-user/environment-db/pdo8_3.php(10): PDO->query('select id, titl...')
#1 {main}
thrown in /home/ec2-user/environment-db/pdo8_3.php on line 10
ここではメッセージを折り返して表示しています。
実行結果の Fatal error
のメッセージに Uncaught PDOException
という内容を確認できます。以降はスローされた PDOException
を適切に処理する方法を学習します。
まとめ
- 例外とは、プログラムにおける予期せぬ事態のこと
- SQLの実行時にはSQLの構文の誤り、データベース接続の失敗、制約の違反など様々な予期せぬ事態が起こりうる
PDO
インスタンスはエラーレポート設定を変更することで異常時にPDOException
をスローできる