runfalk
runfalk

Reputation: 1996

Overriding fetch() for PDO when fetching using foreach

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)
}

Upvotes: 3

Views: 2339

Answers (2)

Dennis Haarbrink
Dennis Haarbrink

Reputation: 3760

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 :)

Upvotes: 0

Daniel Egeberg
Daniel Egeberg

Reputation: 8382

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

Upvotes: 3

Related Questions