Php olası Çoklu Iterators mısınız?

3 Cevap php

Çok VolkerK tarafından CEVAPLARI KONTROL EDİNİZ, o başka bir çözüm sağladı, ama ben cevap olarak iki mesaj işaretleyebilirsiniz olamaz. (


Gün iyi!

I know that C# allows multiple iterators using yield, like described here: http://stackoverflow.com/questions/1754041/is-multiple-iterators-is-possible-in-c

PHP var ve Iterator arayüzü. Bir sınıf için birden fazla yineleme senaryoyu uygulamak mümkün mü?

Daha fazla detay (EDIT):

Örneğin ben sınıf TreeNode tek ağaç düğümü uygulama var. Bütün ağacı sadece biri bu sınıfı kullanılarak ifade edilebilir. Ben BreadthFirst veya DepthFirst sırasını kullanarak, örneğin, geçerli düğümün tüm doğrudan ve dolaylı çocukları yinelenmesi için yineleyicileri sağlamak istiyoruz.

Ben ayrı sınıflar olarak bu Yineleyicilerde uygulayabilirsiniz ama bunu yaparken ben ağaç düğümü bu genel olarak çocuk koleksiyonu bulunuyor maruz gerektiğini gerekir.

C # pseudocode:

 public class TreeNode<T> 
  {
  ...
     public IEnumerable<T> DepthFirstEnumerator
     {
         get
        {
            // Some tree traversal using 'yield return'
        }
     }

     public IEnumerable<T> BreadthFirstEnumerator
     {
         get
         {
             // Some tree traversal using 'yield return'
         }
     }
 }

3 Cevap

Evet, yapabilirsiniz.

foreach(new IteratorOne($obj) as $foo) ....

foreach(new IteratorTwo($obj) as $bar) .....

Aslında, sürece size sınıf yineleyici uygular gibi, ona herhangi bir keyfi IteratorIterator uygulayabilirsiniz. Uygulanan meta Yineleyicilerde söz sınıfı hakkında hiçbir şey bilmek gerekmez, çünkü bu iyi bir şeydir.

Örneğin, böyle bir iterable sınıfı düşünün

class JustList implements Iterator
{
    function __construct() { $this->items = func_get_args(); }
    function rewind()      { return reset($this->items); }
    function current()     { return current($this->items); }
    function key()         { return key($this->items); }
    function next()        { return next($this->items); }
    function valid()       { return key($this->items) !== null; }
}

Biraz meta Yineleyicilerde tanımlamak edelim

class OddIterator extends FilterIterator {
    function accept() { return parent::current() % 2;  }
}

class EvenIterator extends FilterIterator {
    function accept() { return parent::current() % 2 == 0;  }
}

Şimdi temel sınıf meta Yineleyicilerde geçerlidir:

 $list = new JustList(1, 2, 3, 4, 5, 6, 7, 8, 9);

 foreach(new OddIterator($list) as $p) echo $p;  // prints 13579
 foreach(new EvenIterator($list) as $p) echo $p; // prints 2468

GÜNCELLEME: php hiçbir iç sınıfları vardır, böylece en azından, eval başvurmadan, burada biraz şans bitti. Sizin Yineleyicilerde baseclass yapısının farkında ayrı sınıflar, olması gerekir. Sen perde arkasında yineleyicileri örneğini taban sınıftaki yöntemleri sağlayarak daha az zararlı yapabilirsiniz:

 class TreeDepthFirstIterator implements Iterator 
 {
      function __construct($someTree).....
 }


 class Tree
 {
       function depthFirst() { return new TreeDepthFirstIterator($this); }
        ....
 }


 foreach($myTree->depthFirst() as $node).....

Başka bir seçenek yerine foreach lambdas kullanmaktır. Bu güzel ve daha esnek olsa PHP5.3 gerektirir:

 class Tree
 {
        function depthFirst($func) {
              while($node = .....)
                $func($node);

 .....

 $myTree->depthFirst(function($node) {
     echo $node->name;
 });

Amaç için bu sınıfta bir "mod" bayrak var yeterli olabilir, bu yüzden kullanıcı bir ekmek-ilk veya bir derinlik ilk yineleyici sahip seçebilirsiniz.

class Tree {
  const TREE_DEPTH_FIRST = 0;
  const TREE_BREADTH_FIRST = 0;

  protected $mode;
  protected $current;

  public function __construct($mode=Tree::TREE_DEPTH_FIRST) {
    $this->mode = $mode;
  }

  public function setMode($mode) {
    ...
  }

  public function next() {
    $this->current = advance($this->current, $this->mode);
  }  
  ....
}

(Ve ilk soruya kısa cevap: hayır php yield return sözdizimsel şeker yok ve bunu yapmak için dönen konum ne olursa olsun yineleyici gerekir iç özel sınıfları, yani yok ile "orijinal" nesne dış dünyaya teşhir edilmesi gereklidir. muhtemelen (ArrayIterator, sen {[kullanarak önlemek çok şey gibi bir yineleyici nesne için all unsurları "hazırlanıyor" bitirmek istiyorum So 2)]})

Bu kod nasıl bir sınıfta birden fazla yineleyicileri eklemek gösterir.

class TreeNode {

public function getOddIterator () {
  return new OddIterator($this->nodes);
}

public function getEvenIterator () {
  return new EvenIterator($this->nodes);
}

}