Does Iterator work only with numeric arrays?

Advertisements

I saw an example at w3schools:

<?php
// Create an Iterator
class MyIterator implements Iterator {
  private $items = [];
  private $pointer = 0;

  public function __construct($items) {
    // array_values() makes sure that the keys are numbers
    $this->items = array_values($items);
  }

  public function current() {
    return $this->items[$this->pointer];
  }

  public function key() {
    return $this->pointer;
  }

  public function next() {
    $this->pointer++;
  }

  public function rewind() {
    $this->pointer = 0;
  }

  public function valid() {
    // count() indicates how many items are in the list
    return $this->pointer < count($this->items);
  }
}

// A function that uses iterables
function printIterable(iterable $myIterable) {
  foreach($myIterable as $item) {
    echo $item;
  }
}

// Use the iterator as an iterable
$iterator = new MyIterator(["a", "b", "c"]);
printIterable($iterator);
?>

Can current method loop the arrays if it a associative array and not numeric.If yes how can i do it ? Example can we do something like this :

function printIterable(iterable $myIterable) {
  foreach($myIterable as $item => $value) {
    echo  "$item - $value";
  }
}

// Use the iterator as an iterable
$iterator = new MyIterator(["a"=>1, "b"=>2, "c"=>3]);
printIterable($iterator);

When i try it. It print this : 0 – 11 – 22 – 3

>Solution :

PHP handles numeric and associative arrays the same way, there’s no difference when printing them and the same code works for both(well, unless one starts adding fancy features..)

So yes, associative arrays can be printed.

The problem is that your code is assuming that the data array keys are numerical, by initializing the $pointer property to 0(that is, a numerical value). One can get around that either by using the internal pointer of the PHP array($this->items), or keeping an explicit list of the array keys.

Version 1
PHP has functions for traversing arrays, they’re named next(), current(), key() etc and are listed under https://www.php.net/manual/en/ref.array.php. That way the array can be traversed without having an explicit pointer:

while(key($arr) !== null) {
  echo current($arr)."\n";
  next($arr);
}

If the methods specified under https://www.php.net/manual/en/class.iterator.php are implemented in your class(implements Iterator) those functions can then be used, like this:

class MyIterator implements Iterator {
  private $items = [];
  private $pointer = 0;

  public function __construct($items) {
    $this->items = $items;
  }

  public function current() {
    return current($this->items);
  }

  public function key() {
    return key($this->items);
  }
  // ...

As can be seen it’s more or less typing the same calls twice. But if you have a more complex Iterable and other pieces of code is added it might start being worth the work.

Version 2
If you don’t want to rely on the functions from Version 1 you could still use $this->pointer, but you’ll have to keep an explicit list of the array keys:

class MyIterator implements Iterator {
  private $items = [];
  private $keys = [];
  private $pointer = 0;

  public function __construct($items) {
    $this->items = array_values($items);
    $this->keys = array_keys($items);
  }

  public function current() {
    return $this->items[$this->keys[$this->pointer]];

    // Alternative version:
    return $this->items[$this->key()];
  }

  // Return the key of the current element
  public function key() {
    return $this->keys[$this->pointer];
  }

  // Step the array one element, and then return that value
  public function next() {
    // Check that we're not moving out of bounds, if so return null
    // and follow the next() spec.

    ++$this->pointer;
    return $this->items[$this->keys[$this->pointer]];
    
    // Alternative version:
    return $this->current();
  }
  // ...

As can be seen Version 2 creates another array "level" to keep track of(if associative and numeric arrays should both be supported). But it can be done.

Leave a Reply Cancel reply