Статьи

Простые объектные итераторы в PHP

Если вы некоторое время программировали на PHP, вы можете быть знакомы с циклом foreach . Он обеспечивает простой способ анализа каждого элемента в массиве, например


$myArray = array();
$myArray[] = "First item";
$myArray[] = "Second item";
$myArray[] = "Third item";

foreach ($myArray as $i) {
	echo "<p>$i</p>";
}

Помимо массивов, также возможен цикл по объекту. Если ваш объект содержит коллекцию элементов, вы можете использовать цикл foreach для итерации по каждому из них. Неважно, что находится в этой коллекции или как она получена, например

  • записи из базы данных
  • навигационные ссылки
  • имена файлов в каталоге
  • строки текста, прочитанные из файла
  • объекты товара в определенной категории магазина

Итераторы — это предмет, который вселяет страх в сердце многих разработчиков. Они кажутся сложными и часто объясняются неразборчивыми абстрактными ссылками. Их лучше всего объяснить на простом примере, поэтому мы создадим базовый класс, который определяет список веб-технологий:

 
class WebTechnologies
{
	private $tech;

	// constructor
	public function __construct() {
		$this->tech = explode( ',', 'PHP,HTML,XHTML,CSS,JavaScript,XML,XSLT,ASP,C#,Ruby,Python') ;
	}

}

Частный массив $ tech не может быть доступен вне класса. Вы можете сделать его общедоступным или вернуть его содержимое, но итераторы предоставляют более элегантную альтернативу.

Предполагая, что у вас уже есть данные в массиве, самый быстрый способ сделать объект доступным — это реализовать интерфейс IteratorAggregate:

 
class WebTechnologies implements IteratorAggregate
{...

Чтобы завершить код, мы должны определить публичную функцию getIterator () в нашем классе. Это должно вернуть что-то, что может быть повторено — такой объект ArrayIterator с нашим массивом $ tech, переданным его конструктору:

 
// return iterator
public function getIterator() {
	return new ArrayIterator( $this->tech );
}

Теперь мы можем перебирать все элементы массива $ tech. Полный код:

 
class WebTechnologies implements IteratorAggregate
{

	private $tech;

	// constructor
	public function __construct() {
		$this->tech = explode( ',', 'PHP,HTML,XHTML,CSS,JavaScript,XML,XSLT,ASP,C#,Ruby,Python' );
	}
	
	// return iterator
	public function getIterator() {
		return new ArrayIterator( $this->tech );
    }

}

// create object
$wt = new WebTechnologies();

// iterate over collection
foreach ($wt as $n => $t) {
	echo "<p>Technology $n: $t</p>";
}

Отлично. Но что, если коллекция нашего объекта не является массивом? В этой ситуации нам требуются более сложные итераторы… будьте внимательны, скоро появится полное руководство.