2011-11-08 114 views
3

朋友。我知道,這些迭代器已經有很多問題了。 我讀過一些東西,我不是初學者...但我的思想有點卡住了。請幫助我理解我在實踐中如何使用迭代器。使用PHP迭代器

假設,我有一個ORM對象可以從數據庫中選擇實例。和一個實例包含字段,並可以插入,uodate等照常。 我想遍歷一個類型的所有對象,但由於可以有很多這樣的對象,所以我更喜歡用「頁面」來選擇它們。我的代碼:

$limit = 100; 
$offset = 0; 
do 
{ 
    $recs = $orm->select($filter, $sorting, $limit , $offset); 
    $offset += $limit; 
    foreach ($recs as $rec) 
    { 
    // doing something with record 
    } 
} 
while (count($recs) == $limit); 

我覺得迭代器模式在這裏什麼適合,但什麼接口是更好的在這種情況下實施或者一些基礎SPL類?

UPDATE 理想代碼上面迭代可能看起來像:

$iterator = new ORMPagedIterator($ormobject, $filter, $sorting); 
foreach ($iterator as $rec) 
{ 
    // do something with record 
} 

例如所有那些逐頁行爲都在迭代器中。

+0

您可能想詳細說明您的場景。我不明白你的意思是「我喜歡按頁面選擇它們」。此外,查看http://stackoverflow.com/questions/1957133/php-spl-reference-documentation各種SPL相關資源。 – Gordon

+0

「通過頁面」的意思是「通過某些部分」,而不是「一個請求中的所有」。其實,現在我沒有太多時間去閱讀大量的文檔,所以我希望得到一個好的建議。 – dmitry

+0

AFAIK通常在服務器上提取更多數據比在同一查詢中運行更多次更容易 – max4ever

回答

4

一旦達到以前的迭代結束時,我會使用迭代另一個迭代器,並請求下一個迭代的迭代器......好吧,聽起來莫複雜得多,它實際上是:

<?php 
$limit = 100; 
$offset = 0; 

$iter = new NextIteratorCallbackIterator(function($i) use ($orm, $limit, &$offset) { 
    printf("selecting next bunch at offset %d\n", $offset); 
    $recs = $orm->select($filter, $sorting, $limit , $offset); 
    $offset += $limit; 
    if ($recs) { 
     return new ArrayIterator($recs); 
    } 
    return null; // end reached 
}); 

foreach ($iter as $rec) { 
    // do something with record 
} 
?> 

這裏是NextIteratorCallbackIterator的樣本實現:

<?php 
class NextIteratorCallbackIterator implements Iterator { 
    private $_iterator = null; 
    private $_count = 0; 
    private $_callback; 

    public function __construct($callback) { 
     if (!is_callable($callback)) { 
      throw new Exception(__CLASS__.": callback must be callable"); 
     } 
     $this->_callback = $callback; 
    } 

    public function current() { 
     return $this->_iterator !== null ? $this->_iterator->current() : null; 
    } 

    public function key() { 
     return $this->_iterator !== null ? $this->_iterator->key() : null; 
    } 

    public function next() { 
     $tryNext = ($this->_iterator === null); 
     do { 
      if ($tryNext) { 
       $tryNext = false; 
       $this->_iterator = call_user_func($this->_callback, ++$this->_count); 
      } 
      elseif ($this->_iterator !== null) { 
       $this->_iterator->next(); 
       if ($this->_iterator->valid() == false) { 
        $tryNext = true; 
       } 
      } 
     } while ($tryNext); 
    } 

    public function rewind() { 
     $this->_iterator = call_user_func($this->_callback, $this->_count = 0); 
    } 

    public function valid() { 
     return $this->_iterator !== null; 
    } 
} 
?> 

UPDATE:你ORMPagedIterator可以使用NextIteratorCallbackIterator一樣容易實現:

<?php 
class ORMPagedIterator implements IteratorAggregate { 
    function __construct($orm, $filter, $sorting, $chunksize = 100) { 
     $this->orm = $orm; 
     $this->filter = $filter; 
     $this->sorting = $sorting; 
     $this->chunksize = $chunksize; 
    } 

    function iteratorNext($i) { 
     $offset = $this->chunksize * $i; 
     $recs = $this->orm->select($this->filter, $this->sorting, $this->chunksize, $offset); 
     if ($recs) { 
      return new ArrayIterator($recs); 
     } 
     return null; // end reached 
    } 

    function getIterator() { 
     return new NextIteratorCallbackIterator(array($this,"iteratorNext")); 
    } 
} 
?> 
+0

嗯,這很好,謝謝。 – dmitry

+1

我想補充一點,你應該避免選擇大的偏移量,因爲隨着偏移量的增加,你的數據庫將不得不做更多的工作來獲得結果。如果你的結果集是通過它的主鍵排序的,你應該使用前一個結果集的最後一個鍵作爲下一個的開始鍵......這樣你的查詢就不會變慢...... – muhqu