【问题标题】:PHP SPL ArrayIterator v simple foreachPHP SPL ArrayIterator v 简单的 foreach
【发布时间】:2023-03-05 23:16:02
【问题描述】:

好的,正如标题所说:在简单的 foreach 循环中使用 ArrayIterator 的主要好处是什么。

我有一个被用作容器的对象,它的主要职责是存储一个对象数组。

有人建议我让我的类实现 IteratorAggregate 并返回一个带有我的对象数组的 ArrayIterator:像这样:

  public function getIterator()
  {  
    return new ArrayIterator($this->_objs);  
  }

与简单地返回数组然后使用标准 foreach 循环遍历它们相比,我看不到这样做的任何好处。

请有人解释一下为什么这是个好主意?

【问题讨论】:

  • this 会很有趣。

标签: php spl


【解决方案1】:

实现ArrayAccess 的好处很简单:您可以访问整个对象或只是一个非常具体的,甚至private 属性作为数组。

在这个非常简单的示例中,我们使用IteratorArrayAccess 来访问名为$array 的特定属性。

class Foo implements \ArrayAccess, \Iterator
{
    public $pointer = 0;

    private $array = [
        'first value',
        'second value',
        'third value',
    ];

    public function __construct()
    {
        $this->pointer = 0;
    }

    public function current()
    {
        return $this->array[ $this->pointer ];
    }

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

    public function next()
    {
        ++$this->pointer;
    }

    public function rewind()
    {
        $this->pointer = 0;
    }

    public function valid()
    {
        return isset( $this->array[ $this->position ] );
    }
}

我们现在可以像遍历每个数组一样遍历它:

$foo = new Foo();
foreach ( $foo as $key => $value )
{
    print "Index: {$key} - Value: {$value}".PHP_EOL;
}

如前面的示例所示,我们需要实现所有这些方法来循环并访问已经存在的数据。为了实现ArrayAccess,它允许我们实际设置值,我们必须实现另一组方法:

ArrayAccess {
    abstract public boolean offsetExists ( mixed $offset )
    abstract public mixed offsetGet ( mixed $offset )
    abstract public void offsetSet ( mixed $offset , mixed $value )
    abstract public void offsetUnset ( mixed $offset )
}

现在我们可以完全不用编写和重复(当前/键/下一个/等)方法集,只需使用IteratorAggregate。这总结为一个单一的强制方法getIterator()

现在我们会有一个像这样的结果类

class Bar implements \ArrayAccess, \IteratorAggregate
{
    private $array = [];

    public function getIterator()
    {
        return new ArrayIterator( $this->array );
    }
}

我们对$array 属性类拥有完整的数组访问权限。我们可以设置和取消设置值,检查它们是否返回isset,可以循环它们等等。更方便。它与上述所有八种方法完全相同,只需实现IteratorAggregate

最后一点:您可能会再执行一步并实现Traversable。这个接口非常好,因为它允许您强制实现IteratorIteratorAggregate,而无需明确说明实现开发人员需要使用哪一个。它只是说明对象必须是可循环的是强制性的。

$foo = new IteratorContainerController();
$foo->addDependency( Traversable $bar );

这意味着IteratorContainerController() 的依赖项将始终是IteratorIteratorAggregate 实现的对象。因此,某人可以简单地将IteratorAggregate 扔进去,或者,如果他/她需要更细粒度的控制或在设置变量之前对其进行预处理,他/她可以简单地使用Iterator

【讨论】:

    【解决方案2】:

    返回一个数组会暴露对象的内部结构。使用迭代器更抽象。

    我不知道你的班级是做什么的,或者哪个更适合你的情况。但作为一般经验法则,如果唯一实际的用例是迭代数据,那么您应该返回一个迭代器。

    【讨论】:

      猜你喜欢
      • 2012-09-06
      • 2011-05-03
      • 2010-10-24
      • 2011-04-26
      • 1970-01-01
      • 2016-06-22
      • 2012-05-02
      • 2012-09-09
      • 2012-07-05
      相关资源
      最近更新 更多