PHPのPDOの使い方を分かりやすく解説する

PHPでデータベースを操作するのにPDOを使うことが多いが、今回のそのPDOの使い方について解説していく。

そもそもPDOって何?

PDOとはPHP Data Objectsの略で、データベースへの接続、使用を簡単にしてくれるもの。

通常データベースを使用するためには、MySQLやSQLite3などのデータベースの種類によって関数やライブラリを使う必要があるが、PDOであればどのデータベースでも同じような記述で動かすことができる。

PDOは、PHP5.1以降で使うことができ、PHP5.0であればPECL 拡張モジュールとして提供されている。

参考:PHP: はじめに - Manual

PDOでデータベースに接続する

PDOでデータベースに接続するためには、newを使ってPDOインスタンスを作成すれば良い。

例えば、以下のような感じで。

<?php

$host = '127.0.0.1';
$db   = 'sample_db';
$user = 'root';
$pass = 'password';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";

try {
    $pdo = new PDO($dsn, $user, $pass);
} catch (\PDOException $e) {
    throw new \PDOException($e->getMessage(), (int) $e->getCode());
}

上記のコードの例ではMySQLを使っている。

また、データベース接続をする際にtryを使って例外処理を行なっている。これは万が一データベースの設定が適切でなかったり、データベース側に何かしらのトラブルがあった場合を考慮するために行なっている。

PDOのオプションについて

上記のコードでもPDOでデータベースの接続ができるが、よりPDOを使いやすくするためにオプションを設定すると良い。

オプションを使うためのメソッドとしてsetAttributeがあるので、これを使う。

public PDO::setAttribute ( int $attribute , mixed $value ) : bool

setAttributeは、第1引数にオプション名、第2引数にオプションの値を入れる。具体的には以下のように使う。

try {
    $pdo = new PDO($dsn, $user, $pass);
} catch (\PDOException $e) {
    throw new \PDOException($e->getMessage(), (int) $e->getCode());
}

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

上記の例ではsetAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)としているが、これはPDOでの例外エラーを詳細にするためのオプションで、デバッグ時に役立つオプションとなる。

setAttributeは便利なメソッドだが、指定したいオプションが増えてくると何回も書かないと行けなくなり面倒だ。

もし、オプションが複数になる場合は、$options変数みたいな物を用意して、その$options変数をPDOインスタンス生成時に、第4引数として渡してやると良い。

具体的には以下のような感じになる。

<?php

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
    throw new \PDOException($e->getMessage(), (int) $e->getCode());
}

参考:PHP: PDO::setAttribute - Manual

PDOで良く使うオプション

PDOでは、以下の3つがオプションとして使われることが多い。

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION

PDOの例外エラーを詳細にしてくれるオプション。

PDOのエラー文はデータベース接続時は詳細のエラーを表示してくれるが、select文などのSQL実行時にエラーが出た場合は、非常にそっけないエラー文を表示する。

Fatal error: Uncaught Error: Call to a member function execute() on bool in /Users/unknown/pdo.php:26

これだと、execute()がエラーになったことが分かるが、具体的に何が悪くてエラーになったかが分からない。

そこでPDO::ERRMODE_EXCEPTIONのオプションをつけると、以下のようにエラー文が変わる。

Fatal error: Uncaught PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'oreore.users' doesn't exist in /Users/unknown/pdo.php:26

上記のエラーにはBase table or view not found: 1146 Table 'oreore.users' doesn't exist inと書かれており、存在しないテーブルにアクセスしようとしてエラーが出た、と言うことが一発で分かるようになる。

PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC

このオプションを使えば、select文やwhere句などの結果を連想配列として返してくれるようになる。

デフォルトでは、SQLの結果は要素の番号が0,1,2と言う普通の配列として返ってくるが、このオプションをつけることで、以下のように値を返してくれるようになる。

{
  "name" => "tarou",
  "age"  =>  14
}

PDOでSQLを実行する

PDOでSQLを実行するためにはprepareメソッドでSQL文をセットして、executeメソッドでSQLを実行する。

try {
    $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
    throw new \PDOException($e->getMessage(), (int) $e->getCode());
}

$sql = "select * from samples";
$stmt = $pdo->prepare($sql);
$stmt->execute();

prepareメソッドでは、PDOStatementオブジェクトを生成しており、executeメソッドを使うことでPDOStatementオブジェクト内でSQLの結果を保持する、と言う仕組みになっている。

なので、よく初学者が

<?php

$results = $stmt->execute();

上記のコードのように書いて$results変数にSQLの結果があると思い込みがちだが、executeの戻り値はtrue falseのどちらかであり、実際のSQLの結果はPDOStatementオブジェクト(ここでは$stmt)が保持している。

参考:PHP: PDOStatement::execute - Manual

では、どのようにSQLの結果を出すかと言うと、fetchまたはfetchAllを使うと良い。

<?php

$stmt->execute();
    while($row = $stmt->fetch()){
    // 処理
}

上記のコードの$rowには、SQLの結果の一行が配列、または連想配列として取り出される。まとめて全ての結果を取り出したい場合はfetchAllを使うと良い。