3

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)
}
4
  • Can you show some code that does work as expected, and does not work as expected? If you've overridden fetch, it should always work "correctly." Commented Jul 26, 2010 at 8:09
  • Updated with an example. Commented Jul 26, 2010 at 8:37
  • Does it work normally when you replace the foreach with while($r = $s->fetch()) {? Also, keep in mind that the result returned by the parent::fetch call may well not be an array, it could be null. You should probably add an is_array check or something similar. Commented Jul 26, 2010 at 8:42
  • Yes it works as expected. My normal code works, but this starts looping to infinity. This code is just an example to demonstrate the bevaviour. This is not the real code. Commented Jul 26, 2010 at 8:44

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

3 Comments

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: 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 bugs.php.net. It seems reasonable enough that it should call the public fetch() method.
Bug reported: bugs.php.net/bug.php?id=52444. I might try the own iterator approach for now.
0

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

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.