Страница 17 из 20 Итерация по свойствам класса Все переменные класса, доступные в текущем контексте, могут быть перебранны циклом foreach. Такая итерация по свойствам класса может очень пригодится при клонировании объектов. Например, если необходимо создать клон объекта с большим количеством переменных класса, то можно сделать примерно так: class Node { private $value; private $parent; ... private $type; function __clone() { foreach ($that as $propertyName => $propertyValue) { $this->$propertyName = $propertyValue; } } function setParent($value) { $this->parent = $value; } function getParent() { return $this->parent; } function setValue($value) { $this->value = $value; } function getValue() { return $this->value; } ... function setType($value) { $this->type = $value; } function getType() { return $this->type; } } $myNode = new Node(); $myNode->setValue(10); $myNextNode = $myNode->__clone(); print $myNextNode->getValue(); Простой цикл очень хорошо заменяет большое количество присваиваний и избавляет от необходимости синхронизировать присваивания при клонировании со списком всех переменных класса. Очевидным образом, эта итерация не может быть применена к свойствам класса, реализованных через __get()/__set() функции. Изменение стандартной итерации по свойствам Стандартными элементами языка, позволящими итерацию, являются массивы. Но их недостатки очевидны - можно по ошибке поместить в массив элемент другого типа. К массиву не добавишь методы проверки содержимого и т.п. Для введения дополнительных сущностей (классов), позволяющих итерацию по своим элементам, предусмотренно 2 интерфейса: IteratorAggregate и Iterator. interface IteratorAggregate { function getIterator(); // возвращает массив или объект } IteratorAggregate может использоваться, когда данные для итерации можно предоставить в одной из стандарных конструкций PHP, позволяющих итерацию: массива или объекта, реализующего Iterator. Пример использования IteratorAggregate с итерацией по элементам массива: /** Замечание: Этот пример в PHP5 beta 3 не работает. Тем не менее, в документации заявленно, что getIterator() может возвращать массив или объект, реализующий Iterator. Так что к release, надеюсь, исправят. */ class Control implements IteratorAggregate { private $controls; private $name; function __construct() { $this->controls = array(); } function addControl($obj) { $this->controls[$obj->getName()] = $obj; } function setName($value) { $this->name = $value; } function getName() { return $this->name; } // эта функция из IteratorAggregate function getIterator() { return $this->controls; } } $c1 = new Control(); $c1->setName('userId'); $c2 = new Control(); $c2->setName('userName'); $form = new Control(); $form->addControl($c1); $form->addControl($c2); foreach ($form as $ctrl) { echo $ctrl->getName() . ' '; } Этот вариант является только надстройкой над стандартной функциональностью PHP и может использоваться когда до начала итерации можно получить все элементы, участвующие в итрации. Если же этого сделать нельзя (в случае получения записей из базы данных или чтении строк из большого файла), используется другой механизм расширения итерации - реализация интерфейса Iterator. interface Iterator { function rewind(); // переводит итерацию к первому элементу function next(); // подготавливает к выводу следующий элемент function key(); // возвращает ключ текущего элемента function current(); // возвращает текущий элемент function hasMore(); // возвращает true, если есть еще элементы, иначе false } Следующий пример показывает итерацию до нахождения нужного элемента: class Control { private $name; function setName($value) { $this->name = $value; } function getName() { return $this->name; } } class Controls implements Iterator { private $controls; private $controlNames; private $num; function __construct() { $this->controls = array(); } function addControl($obj) { $this->controls[$obj->getName()] = $obj; } // функция использует возможности итерации класса для // поиска контрола с заданным именем function findControl($name) { foreach ($this as $control) { if ($control->getName() == $name) return $control; } return null; } // следующие функции из Iterator function rewind() { $this->controlNames = array_keys($controls); $this->num = 0; } function next() { $this->num++; } function key() { return $this->controlNames($this->num); } function current() { return $this->controls[$this->key()]; } function hasMore() { return $this->num < count($this->controlNames); } } $c1 = new Control(); $c1->setName('userId'); $c2 = new Control(); $c2->setName('userName'); $formControls = new Controls(); $formControls->addControl($c1); $formControls->addControl($c2); $userId = $formControls->findControl('userId'); $userName = $formControls->findControl('userName'); |