仙台の山奥で自転車に乗ったり転んだり

愛車の GIOS でサイクリングしたりポタリングしたり、それをブログに記録してみたり。ロードバイクや自転車や坂のことを書いてみたり。ときたまプログラムのことを忘れないようにメモってみたり。

PDOStatement->bindParamの挙動

原因不明のエラーを追っていたら、整数のはずの変数がいつの間にか文字列型になっていた。
影響の要因が不明でちょっと悩んだが、確認したら単純に「PDOStatement->bindParam」の挙動だった。

class foo
{
    .....

    private function foo()
    {
        try {
            $stmt = $this->db->prepare('INSERT INTO foo VALUES (:id)');
            $stmt->bindParam(':id', $this->id, PDO::PARAM_INT);
            $stmt->execute();
        } catch (PDOException $e) {
            .....
        }
    }

    private function hoge()
    {
        $this->id = 1;
        $this->foo();
        var_dump($this->id); // string(1) "1"
    }

SQLステートメントへのバインドは内部的には文字列データで処理するから、参照としてバインドされる変数は型キャストの副作用を受けるということか?

class PDO_Tester
{
    private $db;

    public function __construct()
    {
        try {
            $this->db = new PDO('sqlite2::memory:');
            $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            throw new RuntimeException('Unable to connect the db: ' . 
                $e->getMessage());
        }
        try {
            $this->db->exec('CREATE TABLE t_test ( id integer, name char(256) )');
        } catch (PDOException $e) {
            throw new RuntimeException('Unable to create the table: ' . 
                $e->getMessage());
        }
    }

    public function test($id, $name)
    {
        try {
            $stmt = $this->db->prepare('INSERT INTO t_test VALUES (:id, :name)');
            $stmt->bindParam(':id', $id, PDO::PARAM_INT);
            $stmt->bindParam(':name', $name, PDO::PARAM_STR, 256);
            $stmt->execute();
        } catch (PDOException $e) {
            throw new RuntimeException('Unable to insert the data: ' . 
                $e->getMessage());
        }

        var_dump($id, $name);
    }
}

$tester = new PDO_Tester;

$id   = 1;
$name = 'hoge';
$tester->test($id, $name);
// string(1) "1"
// string(4) "hoge"

$id   = null;
$name = null;
$tester->test($id, $name);
// NULL
// NULL

$id   = 0.5;
$name = array();
@$tester->test($id, $name);
// string(3) "0.5"
// string(5) "Array"

$id   = -1;
$name = new stdClass;
@$tester->test($id, $name);
// string(2) "-1"
// string(6) "Object"

$id   = true;
$name = false;
@$tester->test($id, $name);
// string(1) "1"
// string(1) "0"

$id   = fopen('php://stdin','r');
$name = fopen('php://stderr','r');
@$tester->test($id, $name);
// string(14) "Resource id #5"
// string(14) "Resource id #6"