|
 |
PHP 5 предоставляет механизм итераторов для получения
списка всех свойств какого-либо объекта, например, для
использования совместно с оператором Разд. foreach в Гл. 16. По умолчанию,
в итерации будут участвовать все свойства, объявленные
как public.
Пример 19-21. Итерация простого объекта
<?php
class MyClass {
public $var1 = 'value 1';
public $var2 = 'value 2';
public $var3 = 'value 3';
protected $protected = 'protected';
private $private = 'private';
}
$class = new MyClass();
foreach($class as $key => $value) {
print "$key => $value\n";
}
|
Результат:
var1 => value 1
var2 => value 2
var3 => value 3
|
|
Как показывает результат, Разд. foreach в Гл. 16
проитерировал все принадлежащие объекту public-свойства.
Кроме того, программист может включить (implement)
в свой класс один из внутренних Разд. Интерфейсы объектов PHP 5,
именуемый Iterator. Это позволит программисту самому определить,
каким именно образом будет осуществляться итерация объекта.
Пример 19-22. Объект Iteration, включающий интерфейс Iterator
<?php
class MyIterator implements Iterator {
private $var = array();
public function __construct($array) {
if (is_array($array) ) {
$this->var = $array;
}
}
public function rewind() {
echo "перемотка в начало\n";
reset($this->var);
}
public function current() {
$var = current($this->var);
echo "текущий: $var\n";
return $var;
}
public function key() {
$var = key($this->var);
echo "ключ: $var\n";
return $var;
}
public function next() {
$var = next($this->var);
echo "следующий: $var\n";
return $var;
}
public function valid() {
$var = $this->current() !== false;
echo "верный: {$var}\n";
return $var;
}
}
$values = array(1,2,3);
$it = new MyIterator($values);
foreach ($it as $a => $b) {
print "$a: $b\n";
}
|
Результатом выполнения этого кода станет:
перемотка в начало
текущий: 1
верный: 1
текущий: 1
ключ: 0
0: 1
следующий: 2
текущий: 2
верный: 1
текущий: 2
ключ: 1
1: 2
следующий: 3
текущий: 3
верный: 1
текущий: 3
ключ: 2
2: 3
следующий:
текущий:
верный:
|
|
Программист также может объявить класс так, чтобы ему
не пришлось описывать все методы, перечисленные в интерфейсе
Iterator, включая интерфейс PHP 5 IteratorAggregate.
Пример 19-23. Объект Iteration, включающий интерфейс IteratorAggregate
<?php
class MyCollection implements IteratorAggregate {
private $items = array();
private $count = 0;
public function getIterator() {
return new MyIterator($this->items);
}
public function add($value) {
$this->items[$this->count++] = $value;
}
}
$coll = new MyCollection();
$coll->add('value 1');
$coll->add('value 2');
$coll->add('value 3');
foreach ($coll as $key => $val) {
echo "key/value: [$key -> $val]\n\n";
}
?>
</pre>
|
Результат:
rewinding
current: value 1
valid: 1
current: value 1
key: 0
key/value: [0 -> value 1]
next: value 2
current: value 2
valid: 1
current: value 2
key: 1
key/value: [1 -> value 2]
next: value 3
current: value 3
valid: 1
current: value 3
key: 2
key/value: [2 -> value 3]
next:
current:
valid:
|
|
Итераторы объектов
chad 0x40 herballure 0x2e com
05-May-2006 06:46
The example code given for valid() will break if the array contains a FALSE value. This code prints out a single "bool(true)" and exits the loop when it gets to the FALSE:
<?php
$A = array(TRUE, FALSE, TRUE, TRUE);
while(current($A) !== FALSE) {
var_dump(current($A));
next($A);
}
?>
Instead, the key() function should be used, since it returns NULL only at the end of the array. This code displays all four elements and then exits:
<?php
$A = array(TRUE, FALSE, TRUE, TRUE);
while(!is_null(key($A))) {
var_dump(current($A));
next($A);
}
?>
mortanon at gmail dot com
14-Oct-2005 08:06
Hier is an example for a CSV Iterator.
<?php
class CsvIterator implements Iterator
{
const ROW_SIZE = 4096;
private $filePointer = null;
private $currentElement = null;
private $rowCounter = null;
private $delimiter = null;
public function __construct($file, $delimiter=',')
{
try {
$this->filePointer = fopen($file, 'r');
$this->delimiter = $delimiter;
}
catch (Exception $e) {
throw new Exception('The file "'.$file.'" cannot be read.');
}
}
public function rewind() {
$this->rowCounter = 0;
rewind($this->filePointer);
}
public function current() {
$this->currentElement = fgetcsv($this->filePointer, self::ROW_SIZE, $this->delimiter);
$this->rowCounter++;
return $this->currentElement;
}
public function key() {
return $this->rowCounter;
}
public function next() {
return !feof($this->filePointer);
}
public function valid() {
if (!$this->next()) {
fclose($this->filePointer);
return false;
}
return true;
}
}
?>
Usage :
<?php
$csvIterator = new CsvIterator('/path/to/csvfile.csv');
foreach ($csvIterator as $row => $data) {
}
?>
markushe at web dot de
06-Aug-2005 11:05
Just something i noticed:
It seems, that when you are implementing the interface Iterator, yout method key() has to return a string or integer.
I was trying to return a object an got this error:
Illegal type returned from MyClass::key()
just_somedood at yahoo dot com
27-Jun-2005 12:20
To clarify on php at moechofe's post, you CAN use the SPL to overide the array operator for a class. This, with the new features of object, and autoloading (among a buch of other things) has me completely sold on PHP5. You can also find this information on the SPL portion of the manual, but I'll post it here as well so it isn't passed up. The below Collection class will let you use the class as an array, while also using the foreach iterator:
<?php
class Collection implements ArrayAccess,IteratorAggregate
{
public $objectArray = Array();
function offsetExists($offset)
{
if(isset($this->objectArray[$offset])) return TRUE;
else return FALSE;
}
function & offsetGet($offset)
{
if ($this->offsetExists($offset)) return $this->objectArray[$offset];
else return (false);
}
function offsetSet($offset, $value)
{
if ($offset) $this->objectArray[$offset] = $value;
else $this->objectArray[] = $value;
}
function offsetUnset($offset)
{
unset ($this->objectArray[$offset]);
}
function & getIterator()
{
return new ArrayIterator($this->objectArray);
}
public function doSomething()
{
echo "I'm doing something";
}
}
?>
I LOVE the new SPL stuff in PHP! An example of usage is below:
<?php
class Contact
{
protected $name = NULL;
public function set_name($name)
{
$this->name = $name;
}
public function get_name()
{
return ($this->name);
}
}
$bob = new Collection();
$bob->doSomething();
$bob[] = new Contact();
$bob[5] = new Contact();
$bob[0]->set_name("Superman");
$bob[5]->set_name("a name of a guy");
foreach ($bob as $aContact)
{
echo $aContact->get_name() . "\r\n";
}
?>
Would work just fine. This makes code so much simpler and easy to follow, it's great. This is exactly the direction I had hoped PHP5 was going!
PrzemekG_ at poczta dot onet dot pl
27-May-2005 04:20
If you want to do someting like this:
<?php
foreach($MyObject as $key => &$value)
$value = 'new '.$value;
?>
you must return values by reference in your iterator object:
<?php
class MyObject implements Iterator
{
public function ¤t()
{
return $something;
}
?>
This won't change values:
<?php
foreach($MyObject as $key => $value)
$value = 'new '.$value;
?>
This will change values:
<?php
foreach($MyObject as $key => &$value)
$value = 'new '.$value;
?>
I think this should be written somewhere in the documentations, but I couldn't find it.
elias at need dot spam
10-Apr-2005 03:15
The MyIterator::valid() method above ist bad, because it
breaks on entries with 0 or empty strings, use key() instead:
<?php
public function valid()
{
return ! is_null(key($this->var));
}
?>
read about current() drawbacks:
http://php.net/current
phpnet at nicecupofteaandasitdown dot com
22-Feb-2005 08:09
You should be prepared for your iterator's current method to be called before its next method is ever called. This certainly happens in a foreach loop. If your means of finding the next item is expensive you might want to use something like this
private $item;
function next() {
$this->item = &$this->getNextItem();
return $this->item;
}
public function current() {
if(!isset($this->item)) $this->next();
return $this->item;
}
knj at aider dot dk
18-Dec-2004 07:19
if you in a string define classes that implements IteratorAggregate.
you cant use the default;
<?
...
public function getIterator() {
return new MyIterator($this-><What ever>);
}
..
?>
at least not if you want to use eval(<The string>).
You have to use:
<?
...
public function getIterator() {
$arrayObj=new ArrayObject($this-><What ever>);
return $arrayObj->getIterator();
}
...
?>
php at moechofe dot com
13-Dec-2004 03:27
<?php
class MyIterator implements Iterator {
private $var = array();
public function __construct() {
$this->var = array( 1,2,3,4 ); }
public function rewind() { reset($this->var); }
public function current() { return current($this->var); }
public function key() { return key($this->var); }
public function next() { return next($this->var); }
public function valid() { return $this->current() !== false; }
}
$it = new MyIterator();
echo $it[0];
?>
| |