PDOで設定できる属性(2/3)
PDO::FETCH_INTO
PDO::FETCH_INTO
は指定された任意のオブジェクトに結果セットをマッピングし取得します。
また、プロパティへのマッピングは通常の参照と同じく行っているので、プロパティ値はpublicにしておくか、__set
でprivateなプロパティに対して値を代入しなければなりません。
class CDEntity { private $ID; private $TITLE; private $CONTENT; } class CDEntity2 { public $ID; public $TITLE; public $CONTENT; public function __get($name){ $prop = strtoupper($name); return $this->$prop; } public function __set($name, $param){ $prop = strtoupper($name); $this->$prop = $param; } } try { $pdo = CZ_PDO::getConnection(); // カラム名と同名のプロパティがprivateであるので // "Cannot access private property"となる //$entity = new CDEntity(); // public のプロパティにするか_setで対応する $entity = new CDEntity2(); $stmt = $pdo->query("SELECT * FROM CD"); $stmt->setFetchMode(PDO::FETCH_INTO, $entity); $rows = $stmt->fetch(); var_dump($rows); } catch (PDOException $e) { var_dump($e->getMessage()); }
上記の実行結果は以下になります。
object(CDEntity2)#2 (3) { ["ID"]=> string(1) "1" ["TITLE"]=> string(5) "HAPPY" ["CONTENT"]=> string(10) "HAPPY SONG" }
PDO::FETCH_FUNC
PDO::FETCH_FUNC
は結果セットのコールバックを指定して取得できます。クラスのメソッド(static)と関数に対して割り当てることができます。
function func_cd($id, $title, $content){ return array("ID" => array( "integer" => (int)$id, "sha1" => sha1($id), "md5" => md5($id), ), "TITLE" => $title, "CONTENT" => $content); } class CD { private $id; private $title; private $content; public function __construct($id, $title, $content){ $this->id = $id; $this->title = $title; $this->content = $content; } public static function method($id, $title, $content){ // コンストラクタを呼び出し、インスタンスを返す。 return new self($id, $title, $content); } } try { $pdo = CZ_PDO::getConnection(); $stmt = $pdo->query("SELECT * FROM CD"); $rows1 = $stmt->fetchAll(PDO::FETCH_FUNC, "func_cd"); var_dump($rows1[0]); $stmt = $pdo->query("SELECT * FROM CD"); $rows2 = $stmt->fetchAll(PDO::FETCH_FUNC, array("CD", "method")); var_dump($rows2[1]); $stmt = $pdo->query("SELECT * FROM CD"); $rows3 = $stmt->fetchAll(PDO::FETCH_FUNC, array(new CD(null,null,null), "method")); var_dump($rows3[2]); $stmt = $pdo->query("SELECT * FROM CD"); $rows4 = $stmt->fetchAll(PDO::FETCH_FUNC, array(CD, "method")); var_dump($rows4[3]); } catch (PDOException $e) { var_dump($e->getMessage()); }
上記の例では通常の関数に結果セットをコールバックし、結果セットを変更しているものと、CD
クラスのスタティックなメソッドに対して結果セットをコールバックしているものの例です。
クラスメソッドにコールバックするときはarray(ClassName, MethodName)
のように指定します。
また、上記の実行結果は以下です。
array(3) { ["ID"]=> array(3) { ["integer"]=> int(1) ["sha1"]=> string(40) "356a192b7913b04c54574d18c28d46e6395428ab" ["md5"]=> string(32) "c4ca4238a0b923820dcc509a6f75849b" } ["TITLE"]=> string(5) "HAPPY" ["CONTENT"]=> string(10) "HAPPY SONG" } object(CD)#4 (3) { ["id:private"]=> string(1) "2" ["title:private"]=> string(3) "SAD" ["content:private"]=> string(8) "SAD SONG" } object(CD)#13 (3) { ["id:private"]=> string(1) "3" ["title:private"]=> string(5) "ANGRY" ["content:private"]=> string(10) "ANGRY SONG" } object(CD)#20 (3) { ["id:private"]=> string(1) "4" ["title:private"]=> string(4) "LOVE" ["content:private"]=> string(9) "LOVE SONG" }
PDO::FETCH_GROUP/PDO::FETCH_UNIQUE
PDO::FETCH_GROUP
とPDO::FETCH_UNIQUE
は結果セットの値をグループ化したり、結果セットから一意な値を取得する場合に使用します。
この2つは単体では使用できず、ビットORして利用します。
try { $pdo = CZ_PDO::getConnection(); $stmt = $pdo->prepare("SELECT * FROM CD limit 3"); $stmt->execute(); var_dump($stmt->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP)); $stmt->execute(); var_dump($stmt->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_UNIQUE)); $stmt->execute(); var_dump($stmt->fetchAll(PDO::FETCH_NUM|PDO::FETCH_UNIQUE)); $stmt->execute(); var_dump($stmt->fetchAll(PDO::FETCH_ASSOC|PDO::FETCH_GROUP)); $stmt->execute(); var_dump($stmt->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE, 1)); $stmt->execute(); var_dump($stmt->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP, 2)); } catch (PDOException $e) { var_dump($e->getMessage()); }
PDO::FETCH_GROUP
やPDO::FETCH_UNIQUE
は、その組合せによって結果セットの表現を広げることができます。
以下に上記の実行結果を載せます。
array(3) { [1]=> array(1) { [0]=> string(5) "HAPPY" } [2]=> array(1) { [0]=> string(3) "SAD" } [3]=> array(1) { [0]=> string(5) "ANGRY" } } array(3) { [1]=> object(stdClass)#3 (2) { ["TITLE"]=> string(5) "HAPPY" ["CONTENT"]=> string(10) "HAPPY SONG" } [2]=> object(stdClass)#4 (2) { ["TITLE"]=> string(3) "SAD" ["CONTENT"]=> string(8) "SAD SONG" } [3]=> object(stdClass)#5 (2) { ["TITLE"]=> string(5) "ANGRY" ["CONTENT"]=> string(10) "ANGRY SONG" } } array(3) { [1]=> array(2) { [0]=> string(5) "HAPPY" [1]=> string(10) "HAPPY SONG" } [2]=> array(2) { [0]=> string(3) "SAD" [1]=> string(8) "SAD SONG" } [3]=> array(2) { [0]=> string(5) "ANGRY" [1]=> string(10) "ANGRY SONG" } } array(3) { [1]=> array(1) { [0]=> array(2) { ["TITLE"]=> string(5) "HAPPY" ["CONTENT"]=> string(10) "HAPPY SONG" } } [2]=> array(1) { [0]=> array(2) { ["TITLE"]=> string(3) "SAD" ["CONTENT"]=> string(8) "SAD SONG" } } [3]=> array(1) { [0]=> array(2) { ["TITLE"]=> string(5) "ANGRY" ["CONTENT"]=> string(10) "ANGRY SONG" } } } array(3) { [1]=> string(5) "HAPPY" [2]=> string(3) "SAD" [3]=> string(5) "ANGRY" } array(3) { [1]=> array(1) { [0]=> string(10) "HAPPY SONG" } [2]=> array(1) { [0]=> string(8) "SAD SONG" } [3]=> array(1) { [0]=> string(10) "ANGRY SONG" } }
PDO::FETCH_SERIALIZE
PDO::FETCH_SERIALIZE
はシリアル化されたクラスオブジェクトを、設定したクラスのunserialize
メソッドにマッピングします。
一般的にSPLのSerializable
インターフェイスを実装したクラスをシリアル化(serialize
メソッド呼び出し)してDBに格納し、取り出すときはunserialize
を呼びオブジェクトを復元します。
PHPのオブジェクト全体をDBに格納している場合に重宝すると思います。
class CDEntity implements Serializable { private $ID; private $TITLE; private $CONTENT; public function __get($name){ $prop = strtoupper($name); return $this->$prop; } public function __set($name, $param){ $prop = strtoupper($name); $this->$prop = $param; } public function serialize(){ $serial = array(); foreach($this as $prop => $value){ $serial[$prop] = $value; } return serialize($serial); } public function unserialize($serialized){ foreach(unserialize($serialized) as $prop => $value){ $this->$prop = $value; } return true; } } try { $pdo = CZ_PDO::getConnection(); $obj[0] = new CDEntity(); $obj[0]->id = 222; $obj[0]->title = "hoge"; $obj[0]->content = "Hello! Hoge"; $obj[1] = new CDEntity(); $obj[1]->id = 333; $obj[1]->content = "Hello! Foo"; $obj[1]->title = "foo"; $obj[2] = new CDEntity(); $obj[2]->id = 444; $obj[2]->title = "bar"; $obj[2]->content = "Hello! Bar"; $stmt = $pdo->prepare( "INSERT INTO CD(ID, TITLE, CONTENT) VALUES(:ID, :TITLE, :CONTENT)"); foreach($obj as $o){ $stmt->bindValue(":ID", $o->id); $stmt->bindValue(":TITLE", $o->title); $stmt->bindValue(":CONTENT", $o->serialize()); $stmt->execute(); } $stmt = $pdo->query("SELECT CONTENT FROM CD where ID > 100"); $rows = $stmt->fetchAll( PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE, "CDEntity"); var_dump($rows); } catch (PDOException $e) { var_dump($e->getMessage()); }
上記の実行結果は以下になります。
array(3) { [0]=> object(CDEntity)#5 (3) { ["ID:private"]=> int(222) ["TITLE:private"]=> string(4) "hoge" ["CONTENT:private"]=> string(11) "Hello! Hoge" } [1]=> object(CDEntity)#7 (3) { ["ID:private"]=> int(333) ["TITLE:private"]=> string(3) "foo" ["CONTENT:private"]=> string(10) "Hello! Foo" } [2]=> object(CDEntity)#8 (3) { ["ID:private"]=> int(444) ["TITLE:private"]=> string(3) "bar" ["CONTENT:private"]=> string(10) "Hello! Bar" } }
シリアル化したオブジェクトをデータベースにそのまま格納することで、オブジェクトをまるごとデータベースに文字列として格納できます。
PHPのオブジェクトや配列でマッピングをするよりもオーバヘッドが少ないので、利用されている方もいるのではないかと思います。
bind時に関する設定項目
PDO::PARAM_で始まる定数
PDO::PARAM_BOOL
PDO::PARAM_NULL
PDO::PARAM_INT
PDO::PARAM_STR
PDO::PARAM_LOB
上記のようなPDO::PARAM_
で始まるPDOの定数は、PDOStatement
でデータ値のバインドをPHPとDBで一致させる場合に使います。
try { $pdo = CZ_PDO::getConnection(); $stmt = $pdo->prepare( "INSERT INTO CD(ID, TITLE, CONTENT) VALUES(?, ?, ?)"); $stmt->bindValue(1, 15, PDO::PARAM_INT); $stmt->bindValue(2, null, PDO::PARAM_NULL); $stmt->bindValue(3, "", PDO::PARAM_STR); $stmt->execute(); $fp = fopen("hoge.jpg", "r"); $stmt->bindValue(1, 16); $stmt->bindValue(2, true, PDO::PARAM_BOOL); $stmt->bindValue(3, $fp, PDO::PARAM_LOB); $stmt->execute(); fclose($fp); var_dump($pdo->query( "SELECT * FROM CD WHERE ID >= 15")->fetchAll(PDO::FETCH_ASSOC)); } catch (PDOException $e){ var_dump($e); }
よく使う例として、PHP変数に""(空文字)やnull、0の値が代入された場合に、その変数の値はDB上でどのように扱うかを定義します。
また、空文字列とnullの扱いをあらかじめ設定するPDO::ATTR_ORACLE_NULLS
というパラメータもあります。
上記の実行結果は以下です。
array(2) { [0]=> array(3) { ["ID"]=> string(2) "15" ["TITLE"]=> NULL ["CONTENT"]=> string(0) "" } [1]=> array(3) { ["ID"]=> string(2) "16" ["TITLE"]=> string(1) "1" ["CONTENT"]=> <<<ここにはバイナリデータが表示されて しまうので注意が必要です。>>> } }
PDO::PARAM_INPUT_OUTPUT
PDO::PARAM_INPUT_OUTPUT
はストアドプロシージャをコールする際のINOUT
パラメータを使用する場合に設定します。
ストアドプロシージャはDBMS自体がその機能を持っていないと、使えないので注意が必要です。
また、SQLレベルでのプロシージャコールとなるので、DBMSごとに発行するSQLを用意する必要があります。
次のサンプルはPostgreSQL 8.1.2を使用するサンプルとなっています。
また、作成したストアドプロシージャは次のとおりです。
CREATE OR REPLACE FUNCTION HOGE(IN arg INTEGER) RETURNS INTEGER AS $$ begin return arg * 1234; end; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION FOO(OUT arg INTEGER) AS $$ begin arg := 123; end; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION BAR(INOUT arg INTEGER) AS $$ begin arg := arg * 1023; end; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION BAZ(IN arg1 INTEGER, OUT arg2 INTEGER) AS $$ begin arg2 := arg1 * 200; end; $$ LANGUAGE plpgsql;
以下、PDOでプロシージャを呼び出す場合のサンプルになります。
try { $pdo = CZ_PDO::getConnection(); $stmt = $pdo->prepare("SELECT HOGE(?)"); $stmt->bindValue(1, 200, PDO::PARAM_INT); $stmt->execute(); var_dump($stmt->fetch(PDO::FETCH_ASSOC)); $stmt = $pdo->prepare("SELECT FOO()"); $stmt->execute(); var_dump($stmt->fetch(PDO::FETCH_ASSOC)); $bar = 700; $stmt = $pdo->prepare("SELECT BAR(?)"); $stmt->bindParam(1, $bar, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT, 100); $stmt->execute(); var_dump($stmt->fetch(PDO::FETCH_ASSOC)); $baz = 123; $stmt = $pdo->prepare("SELECT BAZ(?)"); $stmt->bindParam(1, $baz, PDO::PARAM_INT); $stmt->execute(); var_dump($stmt->fetch(PDO::FETCH_ASSOC)); } catch (PDOException $e){ var_dump($e); }
上記の実行結果です。
array(1) { ["hoge"]=> int(246800) } array(1) { ["foo"]=> int(123) } array(1) { ["bar"]=> int(716100) } array(1) { ["baz"]=> int(24600) }