php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80917 LimitIterator does not end at count
Submitted: 2021-03-29 20:08 UTC Modified: 2021-03-29 20:36 UTC
From: alexandreparent_dev at outlook dot com Assigned:
Status: Open Package: SPL related
PHP Version: Irrelevant OS: All
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: alexandreparent_dev at outlook dot com
New email:
PHP Version: OS:

 

 [2021-03-29 20:08 UTC] alexandreparent_dev at outlook dot com
Description:
------------
LimitIterator will try to iterate beyond $count. If its inner iterator never yield another item nor return, the LimitIterator will not limit at the expected count.

Test script:
---------------
<?php

function generator(): iterable {
  $count = 0;
  while (true) {
    yield $count++;
    echo 'Yielded: ', $count - 1, \PHP_EOL;

    if ($count > 2) {
      while(true);
    }
  }
}

foreach (new \LimitIterator($generator(), 0, 3) as $count) {
  echo 'Iterating: ', $count, \PHP_EOL;
}

Expected result:
----------------
Iterating: 0
Yielded: 0
Iterating: 1
Yielded: 1
Iterating: 2
Yielded: 2

// Hanging here


Actual result:
--------------
Iterating: 0
Yielded: 0
Iterating: 1
Yielded: 1
Iterating: 2

// Exiting here

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-03-29 20:11 UTC] alexandreparent_dev at outlook dot com
I inverted actual and expected results.
 [2021-03-29 20:19 UTC] levim@php.net
I'm pretty sure the test code is wrong based on your expectations; you are incrementing $count and then checking if the count is greater than 2:

yield 0;
if (1 > 2) // false

yield 1;
if (2 > 2) // false

yield 2;
if (3 > 2) // true, but your limit is 3, meaning that you asked for this!

You need to reduce the limit to 2, or increase the comparison to `$count > 3`.
 [2021-03-29 20:20 UTC] levim@php.net
-Status: Open +Status: Feedback
 [2021-03-29 20:36 UTC] levim@php.net
-Status: Feedback +Status: Open
 [2021-03-29 20:36 UTC] levim@php.net
Actually, I agree with you; this _is_ a bug!

It should check the limit before iterating to the next value.
 [2021-03-30 10:18 UTC] rowan dot collins at gmail dot com
A possibly clearer demonstration of what's happening, using an explicit Iterator rather than a Generator: https://3v4l.org/IrAWU

Until the limit is reached, each call to next() on the LimitIterator calls next(), valid(), current(), and key() on the wrapped iterator, in that order. After the limit is reached, it continues to call next(), but none of the other methods.

In a foreach loop, this results in exactly one extra call to next(), but it actually passes through *every* call to next(), unconditionally.
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Mon Sep 20 08:03:36 2021 UTC