大家都知道,数组是可以使用foreach 循环的,我们也可以把一个对象当做数组,做循环操作。
1、对象继承 Iterator 接口
<?php
class MyIterator implements Iterator{
private $_d = array('a','b','c','d');
private $_p = 0;
public function __construct(){
$this->_p = 0;
}
/**
* 返回当前值
*
* @see Iterator::current()
*/
public function current() {
var_dump(__METHOD__);
return $this->_d[$this->_p];
}
/**
* 当前索引加1
*
*
* @see Iterator::next()
*/
public function next() {
var_dump(__METHOD__);
$this->_p++;
}
/**
* 返回当前索引值
*
*
* @see Iterator::key()
*/
public function key() {
var_dump(__METHOD__);
return $this->_p;
}
/**
* 对当前值进行验证
*
* @see Iterator::valid()
*/
public function valid() {
var_dump(__METHOD__);
return isset($this->_d[$this->_p]);
}
/**
* 将数组索引置为0
*
*
* @see Iterator::rewind()
*/
public function rewind() {
var_dump(__METHOD__);
$this->_p = 0;
}
}
$me = new MyIterator();
foreach($me as $key => $value){
var_dump($key) . ':' . var_dump($value);
}
结果如下图:
让我们分析一下:
1、将对象中数组的索引置为0.
2、验证该索引下是否有值。
3、如果有、返回值。
4、返回索引值。
5、调用next函数,索引值加1.
6、重复2、3、4、步奏。如果验证某索引下没有值,就此中断。
缺点:1、我们需要实现这么多的函数(5个。
2、上面说到,如果某一索引下没有值,则就此中断了,不在循环,如果我们的数组是这样的private $_d = array('a','b','c','d',8 => 'f');。那么f值就不会被输出。
我们先来解决第一个缺点。
不实现接口Iterator,实现他的子接口IteratorAggregate
class myData implements IteratorAggregate {
public $property1 = "Public property one";
public $property2 = "Public property two";
public $property3 = "Public property three";
public function __construct() {
$this->property4 = "last property";
}
public function getIterator() {
return new ArrayIterator($this);
}
}
$obj = new myData;
foreach($obj as $key => $value) {
var_dump($key, $value);
echo "\n";
}
输出如下图:
我们只需实现一个方法getIterator就OK了。是不是简单了。我们也可以直接实现MyIterator ,看看出现什么样的结果,自己去尝试下吧。
解决第二个缺点,这就需要我们来完善MyIterator,保证当索引不连续时,也能输出后面的值。封装的思想啊,大家尝试下吧。
下面再说一说Traversable接口,这个接口中什么样的抽样方法都没有,他是Iterator的父接口。最底层的,这个接口一般不会去实现它,如果非得要实现它,记住两点。
1、必须和Iterator、IteratorAggregate两个接口中的某一个或者两个一起用。
2、IteratorAggregate或者Iterator必须放在Traversable前面。如:class MyIterator implements Iterator,Traversable{}。切记。
上面我们说的都是与循环相关的接口,下面我们就来说一说与赋值、销毁值等相关的接口,那就是ArrayAccess 。
首先,一段代码,实现以下该接口
<?php
class MyArray implements ArrayAccess{
private $_d = array('a','v','b','d');
/**
* 检测某个索引下的值是否存在
*
* @see ArrayAccess::offsetExists()
*/
public function offsetExists($offset) {
var_dump(__METHOD__);
return $this->_d[$offset] !== null;
}
/**
* 取得某一索引上的值
*
* @see ArrayAccess::offsetGet()
*/
public function offsetGet($offset) {
var_dump(__METHOD__);
return $this->_d[$offset];
}
/**
* 设置某一索引上的值
*
* @see ArrayAccess::offsetSet()
*/
public function offsetSet($offset, $value) {
var_dump(__METHOD__);
$this->_d[$offset] = $value;
}
/**
* 销毁某一索引处的值
*
*
* @see ArrayAccess::offsetUnset()
*/
public function offsetUnset($offset) {
var_dump(__METHOD__);
$this->_d[$offset] = null;
}
}
$me = new MyArray();
echo $me[0];
echo "<br />";
$me[5] = 't' ;
echo "<br />";
empty($me[1]) ;
echo "<br />";
unset($me[2]) ;
结果如图:
一个小问题,留给大家:
如果我们要测试empty($me[10]);会出现什么样的结果呢,大家试下吧。
实现这几个接口完全是为了封装,使其更好的为我们服务。
最后,仅是个人想法,大家共同交流学习。谢谢