What is the Traversable interface used in PHP?

0

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

For example, the class DatePeriod

Then, when I have implement an interface object with Traversable , an error is generated:

Example:

 class Test implements Traversable{}

Generates:

  

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

Another interesting thing too: it's an empty interface.

After all, what is the actual purpose of Traversable and why can not I implement it?

    
asked by anonymous 04.02.2016 / 14:30

1 answer

2

In order to explain this, I'll have to talk about three interfaces: Iterator, IteratorAggregate, and Traversable .

Let's explain in parts:

According to the PHP Manual (translated by me, more or less so):

  

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

Now this information is important.

  

Interface abstract base that can not be instantiated. Instead, you should use IteratorAggregate or Iterator .

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

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

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

But why two interfaces, instead of one?

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

In the case of IteratorAggregate you only need to implement a method, getIterator , which 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 is Traversable for?

Directly, we can immediately remind you that PHP 5 accepts you to define the type of argument that a function or method should receive. This is called Type Induction. For example, if I want an argument to be of a given class, I should define this in the function / method parameter.

Example:

 function iter(MinhaClasse $objeto) {
 }

But in addition to inducing the class itself that will be accepted in the passage of the argument, this typing also allows you to pass a class that is the parent class, or the interface. So, in addition to PHP checking if that class is passed, it can also check if a particular class implements an interface or is a child 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 I accept the two as a parameter of a function / method, since both define a behavior of the class in relation to iteration? Yes, just use Traversable as type induction.

Taking as an example, the ArrayIterator class in PHP implements Iterator . The ArrayObject class implements IteratorAggregate . Both are iterated with foreach , since 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 made is of paramount importance when you see a function of spl iterator, you understand why the definition of the parameter is Traversable .

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

Function Skeleton:

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

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

    
04.02.2016 / 14:30