Jay Bienvenu
Jay Bienvenu

Reputation: 3291

PHP: Recursive generator that works on arrays, ArrayObjects and generators

I'm making a trait for ArrayObject in PHP 5.6 that returns a generator that walks through the contents of the ArrayObject, recursing through any arrays, ArrayObjects and Generators that it finds. I'm having some trouble getting the logic down. Here's what I have so far:

trait Stream
{
   private function _streamOne($iterator)
   {
     foreach ($iterator as $key => $value) {
       if (is_array($value) || (is_object($value) && $value instanceof \Traversable)) {
         $this->_streamOne($value);
       } else {
         yield $key => $value;
       }
     }
   }
  public function stream()
  {
    return $this->_streamOne($this);
  }
}

Unit test:

final class StreamTestClass extends \ArrayObject
{
    use Stream;
}

$o = new StreamTestClass;
$o->offsetSet('alpha','blah');
$o->offsetSet('gamma',array('zeta'=>'yada','theta'=>'woot'));

$result = $o->stream();
$this->assertTrue($result->valid());
$this->assertEquals('alpha',$result->key());
$this->assertEquals('blah',$result->current());
$result->next();
$this->assertEquals('zeta',$result->key()); // fails asserting that null matches expected 'zeta'
$this->assertEquals('yada',$result->current());
$result->next();
$this->assertEquals('theta',$result->key());
$this->assertEquals('woot',$result->current());
$result->next();
$this->assertFalse($result->valid());

What do I need to do to make this work? The solution must work in PHP 5.6.

Upvotes: 0

Views: 202

Answers (1)

Sammitch
Sammitch

Reputation: 32272

You're not actually yielding anything for the recursion.

trait Stream
{
   private function _streamOne($iterator)
   {
     foreach ($iterator as $key => $value) {
       if (is_array($value) || (is_object($value) && $value instanceof \Traversable)) {
         // Change
         foreach($this->_streamOne($value) as $ikey => $ivalue) {
             yield $ikey => $ivalue;
         }
         // End
       } else {
         yield $key => $value;
       }
     }
   }
  public function stream()
  {
    return $this->_streamOne($this);
  }
}

Upvotes: 1

Related Questions