tags:

views:

48

answers:

2

I have extended PDOStatement and modified the fetch() method to typecast values of the types timestamp and arrays, in PostgreSQL, to DateTime and native array. This works as intended but I can't override the behaviour when using the statement in a foreach.

I have solved this by returning rows into an object implementing ArrayAccess, IteratorAggregate and Countable. However I'm not satisfied with that solution and just want a pure array back.

Example:

class ExtendedStatement extends PDOStatement {
    protected function __construct() {
        $this->setFetchMode(PDO::FETCH_ASSOC);
    }
    public function fetch(
        $fetch_style = PDO::FETCH_ASSOC,
        $cursor_orientation = PDO::FETCH_ORI_NEXT,
        $cursor_offset = 0)
    {
        $r = parent::fetch($fetch_style, $cursor_orientation, $cursor_offset);
        if (is_array($r)) {
            $r["extradata"] = TRUE;
        }
        return $r;
    }
}
$db = new PDO("sqlite::memory:");
$db->setAttribute(
    PDO::ATTR_STATEMENT_CLASS, array("ExtendedStatement", array($db)));
$db->exec("CREATE TABLE example(id INTEGER PRIMARY KEY, name VARCHAR)");
$db->exec("INSERT INTO example(name) VALUES('test')");

// This is what is does
$s = $db->prepare("SELECT * FROM example");
$s->execute();
foreach ($s as $r) {
    var_dump($r);
}
$s->closeCursor();

// This is how I want it to be
$s = $db->prepare("SELECT * FROM example");
$s->execute();
while ($r = $s->fetch()) {
    var_dump($r);
}
$s->closeCursor();

// This is how I want it to be
$s = $db->prepare("SELECT * FROM example");
$s->execute();
var_dump($s->fetch());
$s->closeCursor();

Output:

array(2) {
  ["id"]=>
  string(1) "1"
  ["name"]=>
  string(4) "test"
}
array(3) {
  ["id"]=>
  string(1) "1"
  ["name"]=>
  string(4) "test"
  ["extradata"]=>
  bool(true)
}
array(3) {
  ["id"]=>
  string(1) "1"
  ["name"]=>
  string(4) "test"
  ["extradata"]=>
  bool(true)
}
+1  A: 

The PDOStatement class implements the built-in internals-only Traversable interface. The iterator that it implements bypasses the public PDOStatement::fetch() method.

Daniel Egeberg
I have realised this already, but I still want to hack into it in some way. I had an idea of implementing Iterator, but abandoned it in hope of a better solution.
antennen
@antennen: Well, you have three choices really: 1) patch `ext/pdo/pdo_stmt.c`, 2) use `while` instead, 3) implement your own iterator. Regardless, I would probably recommend you to file a bug at http://bugs.php.net. It seems reasonable enough that it should call the public `fetch()` method.
Daniel Egeberg
Bug reported: http://bugs.php.net/bug.php?id=52444. I might try the own iterator approach for now.
antennen
A: 

I use something like this:

$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$sql = 'select * from table';
$stmt = $db->prepare($sql);
$stmt->execute();

while($row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT))
{
    // do stuff
}

So the only thing you have to do is set some options :)

Dennis Haarbrink
Given that he already has that kind of code in the examples in his question, I'm pretty sure he is aware of that possibility.
Daniel Egeberg