【问题标题】:Decorate an Iterator in PHP - enable skipping在 PHP 中装饰一个迭代器 - 启用跳过
【发布时间】:2021-09-16 06:28:46
【问题描述】:

我有一个类,它基本上是 PHP 的 DirectoryIterator 的装饰器。每个文件的内容由类处理,然后由current() 方法返回。目前,当文件是点文件或文件无法处理时,我从current()方法返回false。但我宁愿跳过点和不可处理的文件,只返回处理过的数据。

附:下面的代码是一个简化的示例。我不想在构造函数中预处理所有文件。

class Pages implements \Iterator
{
    public function __construct(string $path)
    {
        $this->di = new \DirectoryIterator($path);
    }

    public function rewind() {
        return $this->di->rewind();
    }

    public function current() {
        $file = $this->di->current();
        if($file->isDot()) {
            return false;
        }
        $content = file_get_contents($file->getPathName());
        if($content === 'Cannot be processed!') {
            return false;
        }
        return $content;
    }

    public function key() {
        return $this->di->key();
    }

    public function next() {
        return $this->di->next();
    }

    public function valid() {
        return $this->di->valid();
    }
}

【问题讨论】:

  • 我认为在您的current 中,您可以针对现有的false 条件重复调用$this->di->current()。实际上,您最终会得到一个while 循环或类似的循环。
  • @Chris Haas - 感谢您的建议。我发布了我的问题的答案。

标签: php design-patterns iterator decorator


【解决方案1】:

你可以通过扩展已经存在的抽象PHP类FilterIterator 来大大简化你自己答案的代码:

class DirectoryFilterIterator
  extends FilterIterator
{
  public function __construct(string $path) {
    parent::__construct(new DirectoryIterator($path));
  }

  public function accept() : bool {
    $current = parent::current();
    // let's not only ensure it's not a dot but that it's an actual readable file
    if(!$current->isFile() || !$current->isReadable()) {
      return false;
    }
    else {
      $contents = file_get_contents($current->getPathname());
      if($contents === 'Some value') {
        return false;
      }
    }
    
    return true;    
  }
}

foreach(new DirectoryFilterIterator('.') as $key => $value) {
  echo "$key -> $value\n";
}

您还可以看到,我不只是确保该项目不是点,而是确保该项目是一个实际可读的文件,因为我认为这更符合您的意图。


PS:由于您的初衷是创建一个装饰器/包装器,您当然可以将 DirectoryFilterIterator 的构造函数更改为接受 DirectoryIterator

public function __construct(DirectoryIterator $it) {
  parent::__construct($it);
}

...然后将实例化改为:

foreach(new DirectoryFilterIterator(new DirectoryIterator('.')) as $key => $value) {
  echo "$key -> $value\n";
}

【讨论】:

  • 刚刚好,我不知道FilterIterator存在
【解决方案2】:

我终于找到了这个解决方案,希望有人觉得它有帮助。可以将此模式应用于任何修饰的迭代器,有效地以类似于“过滤”迭代器的方式结束。

class FilteredIterator implements \Iterator
{
    protected $currentProcessed = null;
    protected $key = -1; // Keys are maintained by the decorating class

    public function __construct(Iterator $iterator)
    {
        $this->it = $iterator;
    }

    // Iterator interface START -->

    public function rewind() {
        $this->it->rewind();
        $this->forward();
    }

    public function current() {
        return $this->currentProcessed;
    }

    public function key() {
        return $this->key;
    }

    public function next() {
        $this->it->next();
        $this->forward();
    }

    public function valid() {
        return $this->it->valid();
    }

    // <-- Iterator interface END


    protected function forward() : void
    {
        if(!$this->it->valid()) {
            // Stop when iterator is done
            return;
        }
        // Pseudo code, insert expensive processing function here -->
        $content = $this->it->current();
        if($content === 5) {
        // <-- Pseudo code END
            // Skip 
            $this->next();
            return;
        }
        // Update position
        $this->key++;
        // Cache successfully processed step
        $this->currentProcessed = $content;

    }
}

$arrayObject = new ArrayObject([1,2,3,4,5,6]);

$filteredIterator = new FilteredIterator($arrayObject->getIterator());

foreach ($filteredIterator as $key => $value) {
    echo $key . ' -> ' . $value . "\n";
}

//0 -> 1
//1 -> 2
//2 -> 3
//3 -> 4
//4 -> 6

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-06
    • 2014-03-30
    • 2012-05-11
    • 2013-03-30
    • 1970-01-01
    • 2018-09-22
    • 2014-06-15
    • 2011-09-03
    相关资源
    最近更新 更多