1

I'm creating a class that implements Iterator and ArrayAccess. The iterator tests are failing. When I do a print_r() on current($object), I get the underlying array, not the first object.

The code below is a sample from my actual class that demonstrates the issue. This is the first time I have implemented Iterator in one of my classes, so I'm probably doing this wrong somewhere. What do I need to change to make the iterator work properly?

Code:

class Collection implements \ArrayAccess, \Iterator
{
    private $_array = array();

    public function __invoke() { return $this->_array; }
    public function offsetExists($offset) { return array_key_exists($offset, $this->_array); }
    public function offsetGet($offset) { return $this->_array[$offset]; }
    public function offsetSet($offset, $value) { $this->_array[$offset] = $value; }
    public function offsetUnset($offset) { unset($this->_array[$offset]); }
    public function current() { return current($this->_array); }
    public function key() { return key($this->_array); }
    public function next() { return next($this->_array); }
    public function rewind() { return reset($this->_array); }
    public function valid() { return is_null(key($this->_array)); }
}

class TemporaryTest extends \PHPUnit\Framework\TestCase
{

    private $_test_object;

    public function setUp()
    {
        $this->_test_object = new Collection();
        $this->_test_object['alpha'] = 'blah';
        $this->_test_object['beta'] = 'yada';
        $this->_test_object['gamma']  = 'woot';
    }

    public function testIteratorOnInternalArray()
    {
        $o = $this->_test_object;
        $a = $o();
        $this->assertEquals('blah', current($a));
        $this->assertEquals('yada', next($a));
        $this->assertEquals('woot', next($a));
    }

    public function testIterator()
    {
        print_r(current($this->_test_object));
        $this->assertEquals('blah', current($this->_test_object));
        $this->assertEquals('yada', next($this->_test_object));
        $this->assertEquals('woot', next($this->_test_object));
        $this->assertFalse($this->_test_object->valid());
        reset($this->_test_object);
        $this->assertEquals('blah', current($this->_test_object));
    }

    public function testForEach()
    {
        $actual = array();
        foreach ($this->_test_object as $key => $value) { $actual[$key] = $value; }
        $this->assertEquals(array('alpha' => 'blah', 'beta' => 'yada','gamma' =>  'woot'), $actual);
    }
}

Unit test output:

.FArray
(
    [alpha] => blah
    [beta] => yada
    [gamma] => woot
)
F                                                                 3 / 3 (100%)

There were 2 failures:

1) TemporaryTest::testIterator
Array (...) does not match expected type "string".

/Users/mac/Projects/NetShapers/Gears/core/Tests/Unit/TemporaryTest.php:83

2) TemporaryTest::testForEach
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
-    'alpha' => 'blah'
-    'beta' => 'yada'
-    'gamma' => 'woot'
 )

/Users/mac/Projects/NetShapers/Gears/core/Tests/Unit/TemporaryTest.php:97

1 Answer 1

1

What did you expect?

When you call current($a) you actually call system function current() on your collection, not the internal method Collection::current().

Just calll it like this to get what you want:

$this->assertEquals('blah', $a->current());

These methods would be called automatically by the system if you could use your collection in foreach for example.


Additional fixes after comment.

You have an error in valid method, that's why foreach fails for you.

Declaration should look like that:

public function valid() 
{ 
    return !is_null(key($this->_array));
}
Sign up to request clarification or add additional context in comments.

4 Comments

Yes, that's exactly what I expect. Did you see the part where the foreach test fails as well?
@JayBienvenu I've updated the answer with the reason why your foreach fails
So the answer is that I had a typo in valid(), and current() doesn't work with Iterator like count() and other functions do?
@JayBienvenu not exactly. Other functions (next, reset) won't work for you too. testIterator fails on first assertion with current, so you did not see other errors. Please take a look: 3v4l.org/KpE85

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.