Search code examples
phpiteratorcontinue

Implementation of `continue` keyword inside iterator pattern


I found that continue functionality can be implemented in iterator pattern only by recursion. The problem is of course that looping through millions of invalid elements that shall be continued should be ultra slow or ever stack overflow.

How to implement continue keyword without using recursion inside iterator pattern?

PHP code with recursion:

class TableIterator implements \Iterator
{
    private $row;
    private $fileLines;

    public function __construct()
    {
        $this->fileLines = [
            "1, 2, 3, 4, 5, 6, 7, 8",
            "my condition, 9, 10, 11, 12, 13, 14, 15",
            "my condition, 16, 17, 18, 19, 20, 21, 22, 23",
            "24, 25, 26, 27, 28, 29, 30, 31",
            "32, 33, 34, 35, 36, 37, my condition 2, 38",
            "39, 40, 41, 42, 43, 44, 45, 46"
        ];
    }

    public function rewind(): void
    {
        reset($this->fileLines);
    }

    public function current(): array
    {
        return $this->row;
    }

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

    public function next(): void
    {
        next($this->fileLines);
    }

    public function valid(): bool
    {
        $this->row = explode(", ", current($this->fileLines));

        if($this->row[0] === 'my condition')
            $this->continue(); // here is the recursion problem
        
        if($this->row[6] === 'my condition 2')
            return false;

        return true;
    }
    
    private function continue()
    {
        $this->next();
        $this->valid();
    }
}

foreach(new TableIterator() as $key => $value)
    print_r($value);

I would be glad if there is a solution or hack for PHP. Thanks.


Solution

  • This is the solution!

    I will not bother myself in 2021 to explain it. Crawl whole algorithm if you are curious.

    class TableIterator implements \Iterator
    {
        private $row;
        private $fileLines;
    
        public function __construct()
        {
            $this->fileLines = [
                "my condition, 16, 17, 18, 19, 20, 21, 22, 23",
                "my condition, 16, 17, 18, 19, 20, 21, 22, 23",
                "my condition, 16, 17, 18, 19, 20, 21, 22, 23",
                "1, 2, 3, 4, 5, 6, 7, 8",
                "my condition, 9, 10, 11, 12, 13, 14, 15",
                "my condition, 16, 17, 18, 19, 20, 21, 22, 23",
                "24, 25, 26, 27, 28, 29, 30, 31",
                "32, 33, 34, 35, 36, 37, my condition 2, 38",
                "39, 40, 41, 42, 43, 44, 45, 46"
            ];
        }
    
        public function rewind(): void
        {
            reset($this->fileLines);
            
            while($this->continue())
            {
                next($this->fileLines);
            }
        }
    
        public function current(): array
        {
            return $this->row;
        }
    
        public function key(): int
        {
            return key($this->fileLines);
        }
    
        public function next(): void
        {
            do {
                next($this->fileLines);
            }
            while($this->continue());
        }
    
        public function valid(): bool
        {
            if($this->row[6] === 'my condition 2')
                return false;
    
            return true;
        }
        
        private function continue()
        {
            $this->row = explode(", ", current($this->fileLines));
            
            return $this->row[0] === 'my condition' ? true : false;
        }
    }
    
    foreach(new TableIterator() as $key => $value)
    {
        var_dump($value);
    }