2010-07-26 6 views
3

Я продлил PDOStatement и модифицировал метод fetch() для получения значений типа timestamp и массивов типов в PostgreSQL до DateTime и собственного массива. Это работает по назначению, но я не могу переопределить поведение при использовании инструкции в foreach.Переопределение fetch() для PDO при извлечении с использованием foreach

Я решил это, возвращая строки в объект, реализующий ArrayAccess, IteratorAggregate и Countable. Однако я не удовлетворен этим решением и просто хочу вернуть чистый массив.

Пример:

 
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(); 

Выход:

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

Можете ли вы показать код, который делает работу, как и ожидалось, и не работает, как ожидается? Если вы переопределили 'fetch', он всегда должен работать« правильно ». – Charles

+0

Обновлено с примером. – runfalk

+0

Работает ли он нормально, когда вы заменяете foreach на 'while ($ r = $ s-> fetch()) {'? Кроме того, имейте в виду, что результат, возвращаемый вызовом 'parent :: fetch', может не быть массивом, он может быть нулевым. Вероятно, вы должны добавить проверку 'is_array' или что-то подобное. – Charles

ответ

3

PDOStatement класс реализует встроенный внутрикорпусных-только Traversable интерфейс. Итератор, который он реализует, обходит общественный метод PDOStatement::fetch().

+0

Я уже это понял, но я все равно хочу что-то взломать. У меня была идея внедрения Iterator, но я отказался от нее в надежде на лучшее решение. – runfalk

+0

@antennen: У вас есть три варианта: 1) patch 'ext/pdo/pdo_stmt.c', 2) использовать' while' вместо этого, 3) реализовать свой собственный итератор. Независимо от того, я бы, вероятно, рекомендовал вам указать ошибку на http://bugs.php.net. Достаточно разумно, чтобы он вызывал публичный метод 'fetch()'. –

+0

Сообщается об ошибке: http://bugs.php.net/bug.php?id=52444. На данный момент я могу попробовать собственный итератор. – runfalk

-1

я использую что-то вроде этого:

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

Так что единственное, что вам нужно сделать, это установить некоторые опции :)

+0

Учитывая, что он уже имеет такой код в примерах в своем вопросе, я уверен, что он знает об этой возможности. –

 Смежные вопросы

  • Нет связанных вопросов^_^