对象迭代
如未特别标明,文章均属原创。转载请注明出处
by : 柳公子 http://huliuqing.github.io
php官网手册对于遍历对象解释如下:
PHP 5 提供了一种定义对象的方法使其可以通过单元列表来遍历,例如用 foreach 语句。默认情况下,所有可见属性都将被用于遍历。
不过使用简单的foreach遍历对象,仅仅能够遍历出对象实例中可见(public)属性的值。
foreach是如何实现对对象进行遍历的呢?
我们的鸟哥在关于一笔试题(Iterator模式) 一文中分享过foreach源码实现。这边我就拿来主义了:
switch (zend_iterator_unwrap(array, &iter TSRMLS_CC)) {
default:
case ZEND_ITER_INVALID:
.....
break
case ZEND_ITER_PLAIN_OBJECT: {
......
break;
case ZEND_ITER_PLAIN_ARRAY:
.....
break;
case ZEND_ITER_OBJECT:
......
break;
}
具体如何使用foreach
遍历对象,查看示例:
<?php
class Student{
private $_identityCard = '360401190001011018';
public $_name = '三丰';
public $_age = 800;
protected $_bloodType = 'O';
public function __construct(){}
}
$s = new Student();
foreach($s as $key => $v){
echo 'key ',$key ,' val ',$v ,'</br>';
}
//输出
key :_name val 三丰
key :_age val 800
从输出的结果来看,实例化对象的所有可见(public
)属性都给遍历输出出来了。
但是,当我们需要遍历那些非可见对象属性,明显简单的使用foreach
遍历对象就不够用了。
好在PHP中有提供内置遍历接口Iterator
和 IteratorAggregate
完成对象的遍历工作。
关于Iterator与IteratorAggregate接口如下:
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::rewind() 和 Iterator::next()
//方法之后被调用以此用来检查当前位置是否有效
}
IteratorAggregate extends Traversable {
/* 方法 */
abstract public Traversable getIterator ( void )//返回一个外部迭代器
}
我们可以通过实现这两个迭代器接口,定义自己的对象遍历规则
1、通过实现IteratorAggregate接口,完成对象属性遍历
我们只需要实现IteratorAggregate中getIterator()方法完成遍历。
class Kungfu implements IteratorAggregate{
public $_name='飞鸿';
public $_age = 121;
protected $_bloodType = 'O';
private $_isMarried = true;
public function __construct(){}
public function getIterator(){
$members = get_class_vars(__CLASS__);
return new ArrayIterator($members);
}
}
$k = new Kungfu();
foreach($k as $key => $v){
echo 'key ',$key ,' val ',$v ,'</br>';
}
/*
key _name val 飞鸿
key _age val 121
key _bloodType val O
key _isMarried val 1
*/
2、通过实现Iterator接口,完成对象属性遍历
相对于IteratorAggregate
而言,Iterator
接口实现起来稍微麻烦一些,需要在实现类中实现所有5个抽象方法。
不过如果我们需要对迭代的对象,进行具体控制的话,使用Iterator
的话则更合适。
class Language implements Iterator{
private $_lang;
private $_counter=0;
public function __construct(){
$this->_lang = explode(',', 'PHP,C++,C,GO,JAVA,JAVASCRIPT,RUBY,Node.js');
}
public function rewind(){
$this->_counter = 0;
}
public function current(){
//当编程语言的值为JAVA时,返回空
if($this->_lang[$this->_counter] == 'JAVA'){
return null;
}
return $this->_lang[$this->_counter];
}
public function valid(){
return isset( $this->_lang[$this->_counter]);
}
public function next(){
++$this->_counter;
}
public function key(){
return $this->_counter;
}
}
$m = new Language();
foreach($m as $key => $v){
echo 'key ',$key ,' val ',$v ,'</br>';
}
//结果输出
key 0 val PHP
key 1 val C++
key 2 val C
key 3 val GO
key 4 val
key 5 val JAVASCRIPT
key 6 val RUBY
key 7 val Node.js
接口Iterator
中抽象方法的执行顺序如下图所示: