Usando Iteradores para recorrer colecciones en PHP5
Los iteradores nos permiten recorrer de forma fácil colecciones de objetos, de forma similar a como recorreríamos un array o una lista con un while o un foreach. Imaginemos que tenemos una aplicación en la que tenemos una clase Book que representa libros y queremos utilizar una colección de libros. Una forma sería simplemente utilizar un array y utilizar las opciones que ofrece PHP para insertar o eliminar elementos, así como recorrer los existentes. Sin embargo esto podría no ser lo más adecuado desde el punto de vista de orientación a objetos ya que implica un acoplamiento alto entre la forma en la que implementamos la colección (un array) y los diferentes puntos de la apliación desde la que se usa.
En muchos casos es más conveniente crear una nueva clase BookCollection que represente la lógica de una colección, en este caso de libros. Esta clase abstraería a las clases usuarias de la implementación interna que se haga de la colección, que podría ser un array o cualquier otra estructura de datos, permitiendo cambiar esta implementación sin tener que tocar nada en el resto de la aplicación.
La clase BookCollection dispondrá de métodos para añadir y eliminar elementos, pero es también necesario acceder a los elementos de la colección. Un uso frecuente de este tipo de colecciones es tener que recorrerla accediendo una a uno a sus elementos. Lo primero que se nos podría ocurrir sería devolver un array con los elementos, sin embargo esto podría no ser directo si el almacenamiento no se realiza en un array. Para ello la opción más cómoda desde PHP sería que se pudiera utilizar un foreach
sobre la colección.
Desde PHP5 es posible realizar este tipo de recorridos de colecciones mendiante foreach
muy fácilmente utilizando el interfaz Iterator
y haciendo que la colección implemente este interfaz.
El siguiente código muestra una colección de elementos genérica que permite añadir cualquier elemento. Para usarla como colección de libros pueden añadirse directamente items a ella o modificar la clase sustituyendo los métodos addItem y removeItem renombrándolos y haciendo que permitan por ejemplo elementos únicamente de tipo Book.
class ItemCollection implements Iterator { private $_items = null; public function __construct() { $this->_books = array(); } public function addItem($i){ $this->_items[] = $i; } public function removeItem($i){ unset($this->_items[array_search($i, $this->_items)]); } public function rewind() { reset($this->_items); } public function current() { return current($this->_items); } public function key() { return key($this->_items); } public function next() { return next($this->_items); } public function valid() { return $this->current() !== false; } } |
Esta clase utiliza un array para almacenar la información de la colección aunque como hemos visto podría utilizarse cualquier otra estructura de datos sin afectar al resto de la aplicación. Para modificar los datos de la colección dispone de dos métodos que permiten añadir y eliminar elementos. Para que la colección pueda ser accedida mediante un foreach se indica en la definición de la clase que implementa el interfaz Iterator
, lo cual obliga a implementar los métodos rewind
, current
, key
, next
y valid
.
La utilización de la colección es muy sencilla. El siguiente ejemplo muestra como usarla como colección de strings, aunque sería idéntico utilizarla para implementar una colección de cualquier otra clase de tipo de datos.
$ic = new ItemCollection(); $ic->addItem("esto "); $ic->addItem("es "); $ic->addItem("una "); $ic->addItem("prueba"); foreach($ic as $str){ echo $str; } |
Gracias por el ejemplo, he estado leyendo sobre el tema y se agradece un ejemplo como este.