首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PHP SeekableIterator :捕捉OutOfBoundsException还是检查有效()方法?

PHP SeekableIterator :捕捉OutOfBoundsException还是检查有效()方法?
EN

Stack Overflow用户
提问于 2015-05-22 14:01:38
回答 1查看 685关注 0票数 4

因此,我不确定这是否是PHP的错误设计,或者是否有一个理解的逻辑来处理相同接口的不一致结果。

SeekableIterator接口有两个方法(seekvalid),它们要么相互冲突,要么应该相互一致地工作,但我看到了这两个方法。

接口的文档说明seek应该抛出类OutOfBoundsException的异常,但这似乎否定了valid的有用性,除非迭代器位置在抛出异常(显然必须被捕获)之前更新(使valid返回为false)。

三个测试实例

例1.

实现SeekableIterator的自定义类,如文档中的示例所提供:

全班:

代码语言:javascript
复制
class MySeekableIterator implements SeekableIterator {

    private $position;

    private $array = array(
        "first element",
        "second element",
        "third element",
        "fourth element"
    );

    /* Method required for SeekableIterator interface */

    public function seek($position) {
        if (!isset($this->array[$position])) {
            throw new OutOfBoundsException("invalid seek position ($position)");
        }

        $this->position = $position;
    }

    /* Methods required for Iterator interface */

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

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

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

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

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

示例1.测试:

代码语言:javascript
复制
echo PHP_EOL . "Custom Seekable Iterator seek Test" . PHP_EOL;

$it = new MySeekableIterator;

$it->seek(1);
try {
    $it->seek(10);
    echo $it->key() . PHP_EOL;
    echo "Is valid? " . (int) $it->valid() . PHP_EOL;
} catch (OutOfBoundsException $e) {
    echo $e->getMessage() . PHP_EOL;
    echo $it->key() . PHP_EOL; // outputs previous position (1)
    echo "Is valid? " . (int) $it->valid() . PHP_EOL;
}

测试1产出:

代码语言:javascript
复制
Custom Seekable Iterator seek Test
invalid seek position (10)
1
Is valid? 1

示例2:

使用本机ArrayIterator::seek

测试2守则:

代码语言:javascript
复制
echo PHP_EOL . "Array Object Iterator seek Test" . PHP_EOL;

$array = array('1' => 'one',
               '2' => 'two',
               '3' => 'three');

$arrayobject = new ArrayObject($array);
$iterator = $arrayobject->getIterator();

$iterator->seek(1);
try {
    $iterator->seek(5);
    echo $iterator->key() . PHP_EOL;
    echo "Is valid? " . (int) $iterator->valid() . PHP_EOL;
} catch (OutOfBoundsException $e) {
    echo $e->getMessage() . PHP_EOL;
    echo $iterator->key() . PHP_EOL;  // outputs previous position (1)
    echo "Is valid? " . (int) $iterator->valid() . PHP_EOL;
}

测试2产出:

代码语言:javascript
复制
Array Object Iterator seek Test
Seek position 5 is out of range
1
Is valid? 1

例3:

使用本机DirectoryIterator::seek

测试3守则:

代码语言:javascript
复制
echo PHP_EOL . "Directory Iterator seek Test" . PHP_EOL;

$dir_iterator = new DirectoryIterator(dirname(__FILE__));
$dir_iterator->seek(1);
try {
    $dir_iterator->seek(500);  // arbitrarily high seek position
    echo $dir_iterator->key() . PHP_EOL;
    echo "Is valid? " . (int) $dir_iterator->valid() . PHP_EOL;
} catch (OutOfBoundsException $e) {
    echo $e->getMessage() . PHP_EOL;
    echo $dir_iterator->key() . PHP_EOL;
    echo "Is valid? " . (int) $dir_iterator->valid() . PHP_EOL;
}

测试3产出:

代码语言:javascript
复制
Directory Iterator seek Test
90
Is valid? 0

那么,人们如何合理地期望知道是否使用valid()seek($position)之后确认有效位置,同时也预期seek()可能抛出异常而不是更新位置,从而使valid()返回true?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-05-30 18:32:00

这里的directoryIterator::seek()方法似乎不是用异常实现的。相反,它将不返回值,并让valid()处理它。

另一个例子是,ArrayObject::seek()“正确”地工作,并抛出一个OutOfBoundsException

理由很简单:ArrayObject (最有可能,也是大多数定制实现)将事先知道它包含多少个元素,因此可以快速检查其边界。但是,DirectoryIterator必须逐个从磁盘读取目录实体,才能到达给定的位置。它通过在循环中调用valid()next()来做到这一点。这就是为什么key()发生了变化,valid()返回0的原因。

其他迭代器甚至不会触及当前的迭代器状态,并且可以快速确定您的请求是否在其范围内。

在sidenote上:如果要向后查找DirectoryIterator中的位置,它将首先重置迭代器,然后再开始迭代每个元素。因此,如果您在位置1000上,并执行一个$it->seek(999),它实际上将再次迭代999元素。

IMHO,DirectoryIterator不是一个很好的seekableIterator接口的实现。它的目的是快速跳转到迭代器中的某个元素,显然,对于directoryIterator,这是不可行的。相反,必须执行一个完整的迭代,这将导致迭代器状态的改变。

seekableIterator接口对于使用迭代器范围进行操作的filterIterators非常有用。在SPL中,这只是LimitIterator。当你这样做时:

代码语言:javascript
复制
$it = new ArrayIterator(range('a','z'));
$it = new LimitIterator($it, 5, 10));

当limitIterator检测到给定的迭代器已经实现了seekableIterator接口时,它将调用seek()以快速跳转到第5个元素,否则它只会迭代直到到达第5个元素。

结论:当你不能快速跳转到一个位置或检查边界时,不要使用seekableIterator。充其量你什么也得不到,最坏的情况下,你得到的迭代器可以在不知道原因的情况下改变状态。

要回答您的问题:seek()应该抛出一个异常,而不是改变状态。应该将directoryIterator (可能还有其他一些)更改为不实现seekableIterator,或者找出seek()之前有多少个条目(但这并不能解决“反向问题”)。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30398762

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档