2011-11-08 2 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 
} 

일예 모든 페이지 별 페이지 비헤이비어가 반복기 내부에 있습니다.

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

: 실제보다

+0

시나리오에 대해 자세히 설명 할 수 있습니다. 나는 당신이 "나는 그들을 페이지로 선택하는 것을 선호한다"라는 말을 얻지 못한다. 또한 다양한 SPL 관련 리소스에 대한 http://stackoverflow.com/questions/1957133/php-spl-reference-documentation을 확인하십시오. – Gordon

+0

"페이지 단위"는 "한 번에 모든 요청"과 달리 "일부분"을 의미합니다. 사실, 지금은 많은 문서화 작업을 할 시간이별로 없기 때문에 좋은 조언을 얻기를 바랍니다. – dmitry

+0

AFAIK 일반적으로 서버에서 더 많은 데이터를 추출하는 것이 더 쉽습니다. 같은 검색어를 두 번 이상 실행하는 것보다 – max4ever

답변

4

는 이전 반복자의 끝에 도달하면 내가 다른 반복자을 반복하고 다음 반복자를 요청 Iterator를 사용하는 것이이 ... 좋아, 미주리 복잡한 소리

<?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 : 그리고 여기에 NextIteratorCallbackIterator의 샘플 구현입니다 귀하의 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

큰 오프셋으로 선택하지 말아야한다고 덧붙입니다. 옵셋이 증가함에 따라 DB가 결과를 얻기 위해 더 많은 작업을해야하기 때문입니다. 결과 집합이 기본 키로 정렬 된 경우 이전 결과 집합의 마지막 키를 다음 키의 시작 키로 사용해야합니다. 그러면 쿼리가 느려지지 않습니다. – muhqu