PDO

PHP Data Objects(PDO)の使用説明です。
ここではテーブルは下記の4つのフィールドを持っているものとして説明しています。


データベースに接続する

接続データベースとユーザー、パスワードを指定します。切断はnewしたオブジェクトにNULLを設定します。
接続に失敗した場合はPDOException例外がスローされるのでtry,catchで捕捉します。これをしないとFatal Errorが発生してしまいます。

try{
    $addr = 'mysql:host=localhost; dbname=mydb';
    $user = 'root';
    $pass = 'password';
    // 接続
    $pdo = new PDO($addr, $user, $pass);

    $state = $pdo->query('SET NAMES utf-8');
    if($state==false){
        $err = $pdo->errorInfo();
        echo $err[2] . "\n";
    }
}
catch(PDOException $e){
    echo "database open error!!: $addr\n $user\n" . $e->getMessage();
}

$pdo = NULL;    // 切断

SQLを実行する(query)

PDO::query()を使用します。

$table = 'Sample1';
$msg = "UPDATE $table SET val=30 WHERE id=1";
// SQL実行
$state = $pdo->query($msg);
if($state==false){
    $err = $pdo->errorInfo();
    echo $err[2] . "\n";
}

挿入した直近のIDを取得する(lastInsertId)

PDO::lastInsertId()を使います。

$table = 'Sample1';
$msg = "INSERT INTO $table (name, val) VALUES ('minai', 87)";
$state = $pdo->query($msg);
if($state!=false){
    $id = $pdo->lastInsertId();    // => insert された id
    echo "insert id:$id\n";
}
else{
    $err = $pdo->errorInfo();
    echo $err[2] . "\n";
}

レコードの情報を取得する(fetch)

PDOStatement::fetch()を使います。引数には取り出し方を指定します。
取り出す要素をすべて取り出す場合PDOStatement::fetchAll()で取り出せます。

$table = 'Sample1';

$state = $pdo->query("SELECT * FROM  $table WHERE id=1");
// 引数なしだと0からの配列になる。
$row = $state->fetch();
echo $row[0] . "\n";
echo $row[1] . "\n";
echo $row[2] . "\n";

$state = $pdo->query("SELECT * FROM  $table WHERE id=1");
// 連想配列で取得
$row = $state->fetch(PDO::FETCH_ASSOC);
echo $row['id'] . "\n";
echo $row['name'] . "\n";
echo $row['val'] . "\n";

$state = $pdo->query("SELECT * FROM  $table");
// 複数レコードを取得
while($row = $state->fetch()){
    echo $row[0] . "\n";
    echo $row[1] . "\n";
    echo $row[2] . "\n";
}

$state = $pdo->query("SELECT * FROM  $table");
// レコードを連想配列で一気に取得
$rows = $state->fetchAll(PDO::FETCH_ASSOC);
foreach($rows as $row){
    echo $row['id'] . "\n";
    echo $row['name'] . "\n";
    echo $row['val'] . "\n";
}

エラー情報を取得する(errorInfo)

POD::errorInfo(),PDOStatement::errorInfo()からエラー情報を取得できます。
errorInfo()からの値はエラーコード、ドライバーエラーコード、ドライバーエラーメッセージの配列です。

// エラーを出力
function checkPDOError($obj){
    if($obj){
        $err = $obj->errorInfo();
        echo "sql state error code:" . $err[0] . "\n";
        echo "driver error code:" . $err[1] . "\n";
        echo "driver error message:" . $err[2] . "\n";
    }
}
$table = 'Sample1';
// SQL文がおかしい場合について

// PDOからエラーを取得
$state = $pdo->query("SELET * FROM  $table");
checkPDOError($pdo);    // => エラーを出力
checkPDOError($state);    // => stateはfalse

// PDOStatementからエラーを取得
$state = $pdo->prepare("SELET * FROM  $table");
$state->execute();
checkPDOError($pdo);    // => 特に問題はない
checkPDOError($state);    // => エラーを出力

大きいオブジェクトを扱う

フィールドのデータ型をBLOBにします。大きいオブジェクトとは一般的に4KB以上を言うようです。
データを設定するときはPDOStatement::bindParam()やPDOStatement::bindValue()などを使用して引数にPDO::PARAM_LOB指定します。
直接生のデータを渡すことも出来ますし、ファイルのハンドルを渡すこともできます。

$table = 'Sample1';

// データの登録
$fp = fopen('20130708.jpg', 'rb');
$state = $pdo->prepare("UPDATE $table SET data=?  WHERE id=1");
$state->bindParam(1, $fp, PDO::PARAM_LOB);
$state->execute();

// データの取得
$state = $pdo->query("SELECT * FROM  $table WHERE id=1");
$row = $state->fetch(PDO::FETCH_ASSOC);
echo $row['data'] . "\n";
// PDOのドキュメントにはstream_get_contents($row['data'])として取得できると書いてあるが
// 「PHP Warning:  stream_get_contents() expects parameter 1 to be resource」と警告が出て取れなかった・・

トランザクション処理を行う(beginTransaction,commit,rollback)

PDO::beginTransaction(),PDO::commit(),PDO::rollback()を使います。
beginTransaction()でトランザクションを開始、正常に終了したい場合はcommit()、元に戻したい場合はrollback()を呼び出します。もしcommit()かrollback()が呼ばれず処理が終了された場合はrollback()されます。

// 処理の途中で例外を投げてロールバックさせるサンプルコード
$table = 'Sample1';
try{
    // トランザクション開始
    if($pdo->beginTransaction()){

        $msg = "UPDATE $table SET val=100 WHERE id=2";
        $state = $pdo->query($msg);

        // commit する前に例外を投げてrollbackしてみる
        throw new PDOException("Force exception");

        $pdo->commit();    // コミット
    }
}
catch(PDOException $e){
    $pdo->rollback();    // 問題発生!元に戻す
    echo $e->getMessage() . "\n";
}

効率的にSQL文を実行する(プリペアドプロシージャ,ストアドプロシージャ)

PDO::prepare()で基本的なSQL文を設定し、
PDOStatement::bindValue(),PDOStatement::bindParam()で変動するパラメータを設定し、
PDOStatement::execute()でSQL文を実行します。
PDOStatement::bindValue()と違いPDOStatement::bindParam()は与えられた値を参照として受け取ります。

// 設定するパラメータの名前を明示的に指定する場合は「:」を付けた名前にする
$state = $pdo->prepare("UPDATE $table SET name=:name, val=:val WHERE id=:id");
if($state!=false){
    // パラメータの設定
    if($state->bindValue(':name', 'goto', PDO::PARAM_STR)==false){ echo "error bindValue"; }
    if($state->bindValue(':val', 11, PDO::PARAM_INT)==false){ echo "error bindValue"; }
    if($state->bindValue(':id', 1, PDO::PARAM_INT)==false){ echo "error bindValue"; }
    if($state->execute()==false){
        $err = $state->errorInfo();
        echo $err[2] . "\n";
    }
}
else{
    $err = $pdo->errorInfo();
    echo $err[2] . "\n";
}

// 設定するパラメータの名前を明示的に設定しない場合は「?」を付ける
$state = $pdo->prepare("UPDATE $table SET name= ? , val= ?  WHERE id= ? ");
if($state!=false){
    // パラメータの設定
    // bindValue()の第一引数は0からではなく1からであることに注意
    if($state->bindValue(1, 'goto', PDO::PARAM_STR)==false){ echo "error bindValue"; }
    if($state->bindValue(2, 11, PDO::PARAM_INT)==false){ echo "error bindValue"; }
    if($state->bindValue(3, 1, PDO::PARAM_INT)==false){ echo "error bindValue"; }
    if($state->execute()==false){
        $err = $state->errorInfo();
        echo $err[2] . "\n";
    }
}
else{
    $err = $pdo->errorInfo();
    echo $err[2] . "\n";
}