首先要从foreach说起,我们都知道对象,数组和对象可以被foreach语法遍历,数字和字符串却不行。
其实除了数组和对象之外PHP内部还提供了一个 Iterator 接口,实现了Iterator接口的对象,也是可以被foreach语句遍历,当然跟普通对象的遍历就很不一样了。 以下面的代码为例:
class Number implements Iterator{
  protected $key;
  protected $val;
  protected $count;   public function __construct(int $count){
    $this->count = $count;
  }   public function rewind(){
    $this->key = 0;
    $this->val = 0;
  }   public function next(){
  $this->key += 1;
  $this->val += 2;
  }   public function current(){
    return $this->val;
  }   public function key(){
  return $this->key + 1;
  }   public function valid(){
    return $this->key < $this->count;
  }
} foreach (new Number(5) as $key => $value){
  echo "{$key} - {$value}\n";
}

这个例子将输出

1 - 0
2 - 2
3 - 4
4 - 6
5 - 8

关于上面的number对象,被遍历的过程。如果是初学者,可能会出现有点懵的情况。为了深入的了解Number对象被遍历的时候内部是怎么工作的,我将代码改了一下,将接口内的每个方法都尽心输出,借此来窥探一下遍历时对象内部方法的的执行情况。

class Number implements Iterator{
protected $i = 1;
protected $key;
protected $val;
protected $count;
public function __construct(int $count){
$this->count = $count;
echo "第{$this->i}步:对象初始化.\n";
$this->i++;
}
public function rewind(){
$this->key = 0;
$this->val = 0;
echo "第{$this->i}步:rewind()被调用.\n";
$this->i++;
}
public function next(){
$this->key += 1;
$this->val += 2;
echo "第{$this->i}步:next()被调用.\n";
$this->i++;
}
public function current(){
echo "第{$this->i}步:current()被调用.\n";
$this->i++;
return $this->val;
}
public function key(){
echo "第{$this->i}步:key()被调用.\n";
$this->i++;
return $this->key;
}
public function valid(){
echo "第{$this->i}步:valid()被调用.\n";
$this->i++;
return $this->key < $this->count;
}
} $number = new Number(5);
echo "start...\n";
foreach ($number as $key => $value){
echo "{$key} - {$value}\n";
}
echo "...end...\n";

以上代码输出如下

第1步:对象初始化.
start...
第2步:rewind()被调用.
第3步:valid()被调用.
第4步:current()被调用.
第5步:key()被调用.
0 - 0
第6步:next()被调用.
第7步:valid()被调用.
第8步:current()被调用.
第9步:key()被调用.
1 - 2
第10步:next()被调用.
第11步:valid()被调用.
第12步:current()被调用.
第13步:key()被调用.
2 - 4
第14步:next()被调用.
第15步:valid()被调用.
第16步:current()被调用.
第17步:key()被调用.
3 - 6
第18步:next()被调用.
第19步:valid()被调用.
第20步:current()被调用.
第21步:key()被调用.
4 - 8
第22步:next()被调用.
第23步:valid()被调用.
...end...

看到这里,我相信大家对Iterator接口已经有一定认识了。

会发现当对象被foreach的时候,内部的valid,current,key方法会依次被调用,其返回值便是foreach语句的key和value。

循环的终止条件则根据valid方法的返回而定。

如果返回的是true则继续循环,如果是false则终止整个循环,结束遍历。

当一次循环体结束之后,将调用next进行下一次的循环直到valid返回false。

而rewind方法则是在整个循环开始前被调用,这样保证了我们多次遍历得到的结果都是一致的。

Iterator 接口的更多相关文章

  1. Collections+Iterator 接口 | Map+HashMap+HashTable+TreeMap |

    Collections+Iterator 接口 1. Collections 是一个操作 Set.List 和 Map 等集合的工具类 Collections 中提供了大量方法对集合元素进行排序.查询 ...

  2. Iterator接口。集合输出

    在集合中支持以下几种方式. iterator ListIterator foreach输出 emumeration输出. 集合输出的标准操作: 集合输出的时候必须形成以下的思路:只要碰到了集合输出的操 ...

  3. iterator接口

    Iterator用来做遍历,所有实现Collection接口的容器都有一个Iterator的方法以返回一个Iterator接口的对象

  4. java集合 之 Collection和Iterator接口

    Collection是List,Queue和Set接口的父接口,该接口里定义的方法即可用于操作Set集合,也可以用于List和Queue集合.Collection接口里定义了如下操作元素的方法. bo ...

  5. < java.util >-- Iterator接口

    每一个集合都有自己的数据结构,都有特定的取出自己内部元素的方式.为了便于操作所有的容器,取出元素.将容器内部的取出方式按照一个统一的规则向外提供,这个规则就是Iterator接口. 也就说,只要通过该 ...

  6. Java API ——Collection集合类 & Iterator接口

    对象数组举例: 学生类: package itcast01; /** * Created by gao on 15-12-9. */ public class Student { private St ...

  7. 源码阅读—Iterator接口和LIstIterator接口

    在继续看ArrayList源码之前,先了解Iterator接口和ListIterator接口,下篇文章详细讲解ArrayList是如何实现它们的. 我们知道,接口只是一种规范,当继承接口并实现其中的方 ...

  8. Iterator接口(迭代器)

    目录 前言 原理 方法 异常 Iterator接口(迭代器) 前言 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合框架,它是一个对象, ...

  9. 为链表数据结构实现iterator接口

    iterator作用 为所有的数据结构提供统一的访问方式. 接口对象 接口对象一共有3个方法,next()方法.return()方法.throw()方法. next() 必填 用于for..of迭代. ...

随机推荐

  1. Golang面向过程编程-函数

    Golang面向过程编程-函数 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是函数 简单的说函数的作用就是把程序里多次调用的相同的代码部分定义成一份,然后起个名字,所有的 ...

  2. Linux下环境变量设置技巧

    Linux下环境变量设置技巧,不用/etc/profile而是在/etc/profile.d目录下新建特定的shell文件来设置 区别: 1.两个文件都是设置环境变量文件的,/etc/profile是 ...

  3. java中equals和compareTo的区别---解惑

    大多转载自 百度知道,个人整理以便日后阅读. value1.compareTo(value2) == 0 value1.equals(value2) equals的效率高些,compareTo其实就是 ...

  4. 修改tomcat启动窗口的名称

    场景:我们在启动tomcat的时候,一般会出现tomcat窗口,默认窗口名字是tomcat,如果我们想知道这个tomcat的端口号,我们需要查看配置文件,很麻烦有木有.如果我们可以直接把端口号设置在窗 ...

  5. C# 面向对象的new关键字的使用

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...

  6. Linux - openssl 加密

    openssl rand 15 -base64 # 口令生成 openssl sha1 filename # 哈希算法校验文件 openssl md5 filename # MD5校验文件 opens ...

  7. JavaScript之12306自动刷新车票[待完善]

    function refresh(){ var search_btn = document.getElementById("query_ticket"); var result_t ...

  8. class特性

    每个HTML元素都可以附带一个class特性.有时候,你希望有一种方法可以指定多个元素并将这些元素和页面上的其他元素区分出来,而不是单独指定文档中的某个元素. <!DOCTYPE html> ...

  9. 创建Git独立分支

    在使用git进行版本控制的某些场景中我们可能需要在一个项目中建立完全独立的分支,此分支将作为一个独立的版本历史根节点,不与之前任何分支拥有相同的版本祖先. 比如当我们要在一个项目中使用一个分支进行项目 ...

  10. Activity生命周期函数、onSaveInstanceState()和onRestoreInstanceState()的介绍

    http://www.cnblogs.com/tianzhijiexian/p/3885472.html