What is the Traversable interface for in PHP?

Asked

Viewed 300 times

0

In the PHP Handbook we can see that some classes can be iterated with foreach implement an interface called Traversable.

For example, the class DatePeriod

There, when I have implement an object of my own the interface Traversable, an error is generated:

Example:

 class Test implements Traversable{}

Gera:

Class Test must implement interface Traversable as part of either Iterator or Iteratoraggregate

Another interesting thing too: it is an empty interface.

After all, what is the real purpose of Traversable and why it is not possible to implement it?

1 answer

2


To explain this, I will have to talk about three interfaces: Iterator, Iteratoraggregate and the Traversable.

Let’s explain in parts:

According to the Manual for PHP (translated by me, more or less like this):

Traversable: Interface to detect if a class can be iterable with foreach.

Now that information is important.

Interface abstract basis which cannot be instantiated. Instead, you should use IteratorAggregate or Iterator.

You need to understand a point: Traversable serves to detect that a class is or is not eternal via foreach. It is a special interface, used internally by PHP.

PHP asks you to use the interfaces IteratorAggregate or Iterator because these two interface extend the interface Traversable (for those who do not know, in php it is possible one interface inherit the other).

And so, php uses Traversable to know if the class can be iterated with foreach, but to define the behavior you should use Iterator or IteratorAggregate.

But because two interfaces, instead of one?

There is change in the form of implementation. With Iterator you need to implement 5 methods in your class should be iterated, that is, this is the way that will define how it will behave in the foreach.

Already in the case of IteratorAggregate you just need to implement a method, getIterator, that should return another object that implements Iterator, so you can iterate over items in your class.

If the two other interfaces already exist, then what good is Traversable?

Directly, we can immediately remember that PHP 5 accepts you to define the type of argument a function or method should receive. It’s called type induction. For example, if I want an argument to be of a certain class, I should define this in the function/method parameter.

Example:

 function iter(MinhaClasse $objeto) {
 }

However, in addition to inducing the class itself that will be accepted in passing the argument, this typing also allows you to pass a class that is either the parent class, or the interface. So, in addition to PHP checking that that class is passed, it can also check whether a particular class implements an interface or is a daughter of another class.

  class X {}
  class Y extends X{}
  class Z{}
  function eh_valido(X $x) {}

  eh_valido(new X); // SIM
  eh_valido(new Y); // SIM
  eh_valido(new Z); // Não

So if I have a class that implements Iterator and another that implements IteratorAggregate, how would you accept both as a function/method parameter, since both define a class behavior relative to iteration? Yeah, just use it Traversable as type induction.

Taking as an example, the class ArrayIterator in PHP implements Iterator. Already the class ArrayObject implements IteratorAggregate. Both are eternal with foreach, because the implementations of the two inherit Traversable.

Then see the following tests:

 $obj = new ArrayObject;
 $it = new ArrayIterator($obj);


 var_dump($obj instanceof IteratorAggregate); // bool(true)
 var_dump($obj instanceof Iterator); // bool(false)
 var_dump($obj instanceof Traversable); // bool(true)


var_dump($it instanceof Iterator); // bool(true)
var_dump($it instanceof IteratorAggregate); // bool(false)
var_dump($it instanceof Traversable); // bool(true)

So we can do this:

 function itera_isso_pra_mim(Traversable $iterator)
 {
       return get_class($iterator);
 }



itera_isso_pra_mim(new ArrayObject); // string(ArrayObject)
itera_isso_pra_mim(new ArrayIterator); // string(ArrayIterator)
itera_isso_pra_mim(new stdClass); // Gera um erro, pois não implementa nada que herde Traversable

All this explanation I did is of utmost importance so when you see a spl iterator function, you understand why the parameter definition is Traversable.

See an example with the function iterator_to_array (the manual in Portuguese is wrong, you have to look at the original English).

Skeleton of function:

iterator_to_array ( Traversable $iterator [, bool $use_keys = true ] )

As an example, it is possible to use as an argument iterator_to_array the following classes: DatePeriod, ArrayIterator, ArrayObject, SplStack, CallbackFilterIterator among others. All of these implement, indirectly, Traversable.

  • "Abstract base interface ...""beautiful phrase but 'middle' redundant O.o, is there concrete interface? this manual huh ...

  • I also agree @rray. Very strange, but that’s what’s in the manual.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.