概要
PDO(PHP Database Object)によるデータベース操作は、手続き型に比べて、異なるDBMS間の際を隠蔽・吸収してくれるほか、セキュリティー対策も組み込まれている。
基本の流れ
PDOの最も基本的な流れは以下の通り。
- ユーザー情報やデータベース情報からPDOオブジェクトを生成する
- PDO::query()メソッドにSQLクエリーを渡してPDOStatementオブジェクトを得る
- PDOStatementオブジェクトからデータをフェッチする
例外処理などを無視した骨格は以下の通り。
|
$username = 'username'; $password = 'password'; $pdo = new PDO('mysql:host=localhost;charset=utf8mb4;dbname=databasename', $username, $password); $sql = 'SELECT * FROM table;' $stmt = $pdo->query($sql); $resut = []; while ($record = $stmt->fetch(PDO::FETCH_ASSOC) { $result[] = ['id' => $record['id'], 'name' => $record['name'], ...]; } $pdo = null; |
メソッド
PDO::__constructor
PDOのコンストラクター
public PDO::__construct ( string $dsn , string $username = ? , string $passwd = ? , array $options = ? )
dsn
データソースネーム(Data Source Name)。DBMS名やホストなどの情報を文字列で指定する。たとえばlocalhostのMySQLを文字セット・データベースまで含めて指定する場合は以下のように記述する。
'mysql:host=localhost;charset=utf8mb4;dbname=databasename'
charset
で文字コードセットをしている点に注意。
$options
PDOクラス定数と用いた連想配列で指定する。たとえばエラーを例外としてthrowさせたい場合は以下のように指定する。
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
PDO::query
クエリー文字列を与えて、検索結果をPDOStatementオブジェクトとして受け取る。
PDOStatement::fetch()
検索結果を取り出す。一般的なのは、while
文の条件の中でfetch()
メソッドの結果を取り出して、全レコードについて処理を行うケース。以下の例では、クエリーによって抽出された都道府県と市町村を連想配列の配列として格納する。
|
$result = []; while ($record = $stmt->fetch(PDO::FETCH_ASSOC)) { $row = []; $row['pref'] = $record['pref']; $row['city'] = $record['city']; $result[] = $row; } |
PDO::prepare
PDO::query()
による方法は、SQLステートメントがそのまま実行されるためセキュリティー上脆弱。
PDO::prepare()によるプリペアードステートメントとbindValue/bindParamによる値や変数のバインドによれば特定文字のエスケープが行われるため、こちらを使うべき。
PDO::lastInsertId
最後に登録されたレコードのIDを返す。MySQLの場合引数は不要。戻り値はstring。
雛形
PDO::query
レコード数のカウント
SQLのCOUNT
の結果1行からデータを読む。以下の例では、id列をカウントした結果が1行で返されるのをfetchColumn()
でカラム指定してデータを取得している。
|
$sql = "SELECT COUNT(id) FROM my_table"; $stmt = $pdo->query($sql); $num_records = $stmt->fetchColumn(0); |
あるいはPDO::rowCount()
メソッドを使ってもよい。この場合はSELECT
で何かのカラムを読み込めばよい。
|
$sql = 'SELECT id FROM my_table'; $stmt = $pdo->query($sql); $num_records = $stmt->rowCount(); |
列の全データの取得
検索したい列を抽出し、PDOStatement::fetchAll()
で配列として取り出す。以下の例ではpref
カラムの全データを取り出し、配列$pref_name
に格納している。
|
$sql = "SELECT pref FROM my_table"; $stmt = $pdo->query($sql); $pref_names = $stmt->fetchAll(PDO::FETCH_COLUMN); |
複数列データの連想配列への格納
以下はクエリーの結果を格納する方法の一つ。各レコードをカラム名をキーとした連想配列とし、それを1つの配列に収めている。
|
$sql = "SELECT zipcode, pref, city, addr FROM addr_table; $stmt = $pdo->query($sql); $result = []; while ($record = $stmt->fetch(PDO::FETCH_ASSOC)) { $row = []; $row['zipcode'] = $record['zipcode']; $row['pref'] = $record['pref']; $row['city'] = $record['city']; $row['addr'] = $record['addr']; $result[] = $row; } |
例外処理
PDOに例外をthrowさせるには、コンストラクターで以下のようにクラス変数で指定する。
|
try { $pdo = new PDO('mysql:host=localhost;charset=utf8mb4;dbname=my_db', $username, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); // ..... } catch (PDOException $e) { // 例外に対する処理 } |
トランザクション
3つのメソッドで簡明に処理できる(PDOによるトランザクションの確認)。
|
$pdo = new PDO($dsn, $user, $pass, $option); try { $pdo->beginTransaction(); // $pdo->query()などの操作 $pdo->commit(); } catch (PDOException $e) { $pdo->rollBack(); // トランザクション失敗時の処理 } |
commit()
メソッド、rollBack()
メソッドはbeginTransaction()
が成功していないと例外になるので注意。
beginTransaction()
はトランザクションが開始できない場合に例外を投げる。
PDOによるトランザクションの確認はこちらを参照。