jjzjj

PHP 可搜索迭代器 : catch OutOfBoundsException or check valid() method?

coder 2024-04-16 原文

所以我不确定这是否是 PHP 的错误设计,或者是否存在处理同一界面的不一致结果的可理解逻辑。

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

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

三个测试例子

例子1.

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

类(class):

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. 测试:

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 输出:

Custom Seekable Iterator seek Test
invalid seek position (10)
1
Is valid? 1

例子2:

使用原生 ArrayIterator::seek

测试2代码:

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 输出:

Array Object Iterator seek Test
Seek position 5 is out of range
1
Is valid? 1

示例 3:

使用 native DirectoryIterator::seek

测试 3 代码:

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 输出:

Directory Iterator seek Test
90
Is valid? 0

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

最佳答案

似乎 directoryIterator::seek()这里的方法没有异常实现。相反,它不会返回任何值,并让 valid()处理它。

你的另一个例子,ArrayObject::seek()确实“正确”工作并抛出 OutOfBoundsException .

推理很简单:ArrayObject (很可能,大多数自定义实现也是如此)会事先知道它包含多少元素,因此可以快速检查它的边界。 DirectoryIterator但是,必须从磁盘中逐个读取目录实体才能到达给定位置。它通过字面上调用 valid() 来实现和 next()在一个循环中。这就是为什么 key()已经改变,并且valid()返回 0 .

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

旁注:如果您想在 DirectoryIterator 中向后查找位置,它将首先重置迭代器,然后再次开始迭代每个元素。所以如果你在位置 1000,做 $it->seek(999) ,它实际上会再次迭代 999 个元素。

恕我直言,DirectoryIterator不是 seekableIterator 的良好实现界面。它旨在快速跳转到迭代器中的某个元素,显然,使用 directoryIterator 这不是可行的。相反,必须进行完整的迭代,这会导致迭代器状态发生变化。

seekableIterator interface 对于 filterIterators 很有用,它对迭代器的范围做一些事情。在 SPL 中,这只是 LimitIterator .当你这样做时:

$it = new ArrayIterator(range('a','z'));
$it = new LimitIterator($it, 5, 10));

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

结论:不要使用 seekableIterator当您无法快速跳到某个位置或检查边界时。最好的情况是您什么也得不到,最坏的情况是您会得到不知道为什么会改变状态的迭代器。

回答您的问题:seek()应该抛出异常而不改变状态。 directoryIterator (也许还有其他人)应该改为不实现 seekableIterator ,或找出 seek() 之前有多少条目(但这并不能解决向后搜索问题时的“倒带”)。

关于PHP 可搜索迭代器 : catch OutOfBoundsException or check valid() method?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30398762/

有关PHP 可搜索迭代器 : catch OutOfBoundsException or check valid() method?的更多相关文章

  1. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  2. Ruby 元类 : why three when defined singleton methods? - 2

    让我们计算MRI范围内的类别:defcount_classesObjectSpace.count_objects[:T_CLASS]endk=count_classes用类方法定义类:classAdefself.foonilendend然后运行:putscount_classes-k#=>3请解释一下,为什么是三个? 最佳答案 查看MRI代码,每次你创建一个Class时,在Ruby中它是Class类型的对象,ruby会自动为这个新类创建“元类”类,这是另一个单例类型的Class对象。C函数调用(class.c)是:rb_define

  3. ruby-on-rails - Rails 中的 NoMethodError::MailersController#preview undefined method `activation_token=' for nil:NilClass - 2

    似乎无法为此找到有效的答案。我正在阅读Rails教程的第10章第10.1.2节,但似乎无法使邮件程序预览正常工作。我发现处理错误的所有答案都与教程的不同部分相关,我假设我犯的错误正盯着我的脸。我已经完成并将教程中的代码复制/粘贴到相关文件中,但到目前为止,我还看不出我输入的内容与教程中的内容有什么区别。到目前为止,建议是在函数定义中添加或删除参数user,但这并没有解决问题。触发错误的url是http://localhost:3000/rails/mailers/user_mailer/account_activation.http://localhost:3000/rails/mai

  4. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  5. ruby-on-rails - Nokogiri:使用 XPath 搜索 <div> - 2

    我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll

  6. ruby - 怎么来的(a_method || :other) returns :other only when assigning to a var called a_method? - 2

    给定以下方法:defsome_method:valueend以下语句按我的预期工作:some_method||:other#=>:valuex=some_method||:other#=>:value但是下面语句的行为让我感到困惑:some_method=some_method||:other#=>:other它按预期创建了一个名为some_method的局部变量,随后对some_method的调用返回该局部变量的值。但为什么它分配:other而不是:value呢?我知道这可能不是一件明智的事情,并且可以看出它可能有多么模棱两可,但我认为应该在考虑作业之前评估作业的右侧...我已经在R

  7. ruby - 使用 rbenv 和 ruby​​-build 构建 ruby​​ 失败,出现 undefined symbol : SSLv2_method - 2

    我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby​​2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby​​-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm

  8. ruby - 如何搜索有用的 ruby - 2

    寻找有用的ruby的好网站是什么? 最佳答案 AgileWebDevelopment列出插件(虽然不是ruby​​gems,我不确定为什么),并允许人们对它们进行评级。RubyToolbox按类别列出gem并比较它们的受欢迎程度。Rubygems有一个搜索框。StackOverflow对最有用的rails插件和ruby​​gems有疑问。 关于ruby-如何搜索有用的ruby,我们在StackOverflow上找到一个类似的问题: https://stacko

  9. ruby - 如何搜索、递增和替换 Ruby 字符串中的整数子字符串? - 2

    我有很多这样的文档:foo_1foo_2foo_3bar_1foo_4...我想通过获取foo_[X]的所有实例并将它们中的每一个替换为foo_[X+1]来转换它们。在这个例子中:foo_2foo_3foo_4bar_1foo_5...我可以用gsub和一个block来做到这一点吗?如果不是,最干净的方法是什么?我真的在寻找一个优雅的解决方案,因为我总是可以暴力破解它,但我觉得有一些正则表达式技巧值得学习。 最佳答案 我(完全)不懂Ruby,但类似这样的东西应该可以工作:"foo_1foo_2".gsub(/(foo_)(\d+)/

  10. ruby - "undefined method"用于 rails 模型 - 2

    我正在使用带有Rails的Devise,我想添加一个方法“getAllComments”,所以我这样写:classUser在我的Controller中:defdashboard@user=current_user@comments=@user.getAllComments();end当我访问我的url时,我得到了undefinedmethod`getAllComments'for#我做错了什么?谢谢 最佳答案 因为getAllComments是一个类方法,而您正试图将其作为实例方法访问。您要么需要访问它:User.getAllCom

随机推荐