Iteración de objetos

PHP 5 ofrece una manera para definir objetos, por lo que es posible recorrer una lista de elementos con, por ejemplo, una sentencia foreach. Por defecto, se utilizarán todas las propiedades visibles para la iteración.

Ejemplo #1 Iteración simple de un objeto

<?php
class MiClase
{
public
$var1 = 'valor 1';
public
$var2 = 'valor 2';
public
$var3 = 'valor 3';

protected
$protected = 'variable protegida';
private
$private = 'variable privada';

function
iterateVisible() {
echo
"MiClase::iterateVisible:\n";
foreach (
$this as $clave => $valor) {
print
"$clave => $valor\n";
}
}
}

$clase = new MiClase();

foreach(
$clase as $clave => $valor) {
print
"$clave => $valor\n";
}
echo
"\n";


$clase->iterateVisible();

?>

El resultado del ejemplo sería:

var1 => valor 1
var2 => valor 2
var3 => valor 3

MiClase::iterateVisible:
var1 => valor 1
var2 => valor 2
var3 => valor 3
protected => variable protegida
private => variable privada

Como se muestra en la salida, foreach recorre todas las propiedades visibles a las que se pueden acceder.

Para dar un paso más, se puede implementar la interfaz Iterator. Esto permite al objeto decidir cómo será iterado y qué valores estarán disponibles en cada iteración.

Ejemplo #2 Iteración de un objeto implementando Iterator

<?php
class MiIterador implements Iterator
{
private
$var = array();

public function
__construct($array)
{
if (
is_array($array)) {
$this->var = $array;
}
}

public function
rewind()
{
echo
"rebobinando\n";
reset($this->var);
}

public function
current()
{
$var = current($this->var);
echo
"actual: $var\n";
return
$var;
}

public function
key()
{
$var = key($this->var);
echo
"clave: $var\n";
return
$var;
}

public function
next()
{
$var = next($this->var);
echo
"siguiente: $var\n";
return
$var;
}

public function
valid()
{
$clave = key($this->var);
$var = ($clave !== NULL && $clave !== FALSE);
echo
"válido: $var\n";
return
$var;
}

}

$valores = array(1,2,3);
$it = new MiIterador($valores);

foreach (
$it as $a => $b) {
print
"$a: $b\n";
}
?>

El resultado del ejemplo sería:

rebobinando
válido: 1
actual: 1
clave: 0
0: 1
siguiente: 2
válido: 1
actual: 2
clave: 1
1: 2
siguiente: 3
válido: 1
actual: 3
clave: 2
2: 3
siguiente:
válido:

La interfaz IteratorAggregate se puede usar como alternativa para implementar todos los métodos de Iterator. IteratorAggregate solamente requiere la implementación de un único método, IteratorAggregate::getIterator(), el cual debería devolver una instancia de una clase que implemente Iterator.

Ejemplo #3 Iteración de un objeto implementando IteratorAggregate

<?php
class MiColección implements IteratorAggregate
{
private
$items = array();
private
$cuenta = 0;

// Se requiere la definición de la interfaz IteratorAggregate
public function getIterator() {
return new
MiIterador($this->items);
}

public function
add($valor) {
$this->items[$this->cuenta++] = $valor;
}
}

$colección = new MiColección();
$colección->add('valor 1');
$colección->add('valor 2');
$colección->add('valor 3');

foreach (
$colección as $clave => $val) {
echo
"clave/valor: [$clave -> $val]\n\n";
}
?>

El resultado del ejemplo sería:

rebobinando
actual: valor 1
válido: 1
actual: valor 1
clave: 0
clave/valor: [0 -> valor 1]

siguiente: valor 2
actual: valor 2
válido: 1
actual: valor 2
clave: 1
clave/valor: [1 -> valor 2]

siguiente: valor 3
actual: valor 3
válido: 1
actual: valor 3
clave: 2
clave/valor: [2 -> valor 3]

siguiente:
actual:
válido:

Nota:

Para más ejemplos de iteradores, véase la extensión SPL.

Nota:

Los usuarios de PHP 5.5 y posteriores pueden investigar los generadores, los cuales posibilitan una forma alternativa de definir iteradores.