PHP 对象迭代功能详解

   这两天在翻看PHP手册,进一步对PHP类加以理解和掌握。本文是对“PHP对象迭代”做相关总结和学习。

   PHP5提供了一种迭代对象的功能,就如同使用数组一样,可以通过使用foreach循环来遍历对象当中的属性。通常,我们使用foreach迭代对象,仅仅可以遍历外部可见的属相值(可见性为public的类成员变量)。

   简单对象迭代示例

<?php
class MyClass
{
    public $var1 = ‘value 1‘;
    public $var2 = ‘value 2‘;
    public $var3 = ‘value 3‘;
    protected $protected = ‘protected var‘;
    private   $private   = ‘private var‘;
    function iterateVisible() {
       echo "MyClass::iterateVisible:\n";
       foreach($this as $key => $value) {
           print "$key => $value\n";
       }
    }
}
$class = new MyClass();
foreach($class as $key => $value) {
    print "$key => $value\n";
}
echo "\n";
$class->iterateVisible();
?>

   以上示例输出如下:

 

var1 => value 1
var2 => value 2
var3 => value 3
MyClass::iterateVisible:
var1 => value 1
var2 => value 2
var3 => value 3
protected => protected var
private => private var


   简单的foreach虽然也能够完成对象的遍历功能,但是如果需要使用对象遍历功能,我们可能需要实现Iterator接口或者IteratorAggregate接口达到更好的遍历效果。


   Iterator 与 IteratorAggregate接口实际都实现了另一个接口Traversable。有关Traversable接口内容,可参看Traversable官方文档  和我翻译文章 正确理解PHP Traversable 接口

   

   实现Iterator接口

   Iterator接口,可在内部迭代自己的外部迭代器或类的接口


   Iterator接口定义了以下抽象的方法:

   

Iterator extends Traversable {
/* 方法 */
abstract public mixed current ( void )
abstract public scalar key ( void )
abstract public void next ( void )
abstract public void rewind ( void )
abstract public boolean valid ( void )
}

 

  实现Iterator接口的类MyIterator。我们需要实现所有Iterator接口,未实现的方法体

class MyIterator implements Iterator{
    private $_var = array(
        "firstelement",
        "secondelement",
        "lastelement",
    ); 
                                                                                                                                                                                                                                                                                                          
    public function __construct(){}
                                                                                                                                                                                                                                                                                                          
    public function rewind(){
        echo __METHOD__ ,‘<br/>‘;
        return reset($this->_var);
    }
                                                                                                                                                                                                                                                                                                          
    public function current(){
        echo __METHOD__ ,‘<br/>‘;
        $current = current($this->_var);
        return $current;       
    }
                                                                                                                                                                                                                                                                                                          
    public function next(){
        echo __METHOD__ ,‘<br/>‘;
        $next = next($this->_var);
        return $next;
    }
                                                                                                                                                                                                                                                                                                          
    public function key(){
        echo __METHOD__ ,‘<br/>‘;
        $key = key($this->_var);
        return $key;
    }
                                                                                                                                                                                                                                                                                                          
    public function valid(){
        echo __METHOD__ ,‘<br/>‘;
        $valid = $this->current() !== false;
        return $valid;
    }  
}
$myIterator = new MyIterator();
foreach($myIterator as $key => $value){
    echo $key , ‘ ----- ‘, $value ,‘<br/>‘;
}

 运行结果:

MyIterator::rewind
MyIterator::valid
MyIterator::current
MyIterator::current
MyIterator::key
0 ----- firstelement
MyIterator::next
MyIterator::valid
MyIterator::current
MyIterator::current
MyIterator::key
1 ----- secondelement
MyIterator::next
MyIterator::valid
MyIterator::current
MyIterator::current
MyIterator::key
2 ----- lastelement
MyIterator::next
MyIterator::valid
MyIterator::current

从运行结果我们可以很清晰的看到Iterator接口中方法的调用顺序如下图所示

第一次迭代

1:重置指针         rewind()

2:判断是否存在属性 valid()

3:存在获取当前值   current()

4:获取当前值的键名 key()


第二次以后迭代

1:获取对象内下一个属性 next();

2:判断是否存在属性 valid()

3:存在获取当前值   current()

4:获取当前值的键名 key()

 










实现IteratorAggregate接口

   IteratorAggregate接口 :创建外部迭代器的接口。

   Iterator接口定义了以下抽象的方法:

IteratorAggregate extends Traversable {
/* 方法 */
abstract public Traversable getIterator ( void )
}

 


   定义实现Iteratorgate类MyCollection

<?php
class MyCollection implements IteratorAggregate
{
    private $items = array();
    private $count = 0;
    // Required definition of interface IteratorAggregate
    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";
}
?>

   运行结果如下:

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:

   

通过实现IteratorAggregate接口,我们可以简单的实现getIterator()方法,达到遍历对象的功能

 

扩展阅读

关于一笔试题(Iterator模式)

正确理解PHP Traversable 接口

SPL迭代器

本文出自 “柳公子” 博客,请务必保留此出处http://phpnotes.blog.51cto.com/5625189/1358889

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。