php迭代器Iterator接口
以前也看过迭代器Iterator接口,感觉不如yied好用,因此实际工作中并没有用到过。
今天看了一篇网上的博客(https://www.cnblogs.com/wwjchina/p/7723499.html),想起自己之前看过的迭代器Iterator,好像也是这么讲的,然而看完后,发现好像更迷糊了。
下面我说一下该博客讲解的内容,让我迷惑的地方
1、php提供了一个语法结构用于遍历数组和对象 foreach
2、而foreach则不能直接遍历对象里面的属性,需要通过迭代器(预定义接口 Iterator)
先来看这两条,首先看第1条,
- foreach可以遍历数组和对象。遍历数组大家都知道,foreach遍历对象可能就会有疑问了。
- 刚开始我以为遍历对象是将对象中所有的属性和方法都遍历出来,后来发现不是。
- foreach遍历对象时,仅遍历对象属性。对象的属性是一个集合数组, 因此foreach遍历对象时就是遍历对象中所有的公开属性,private遍历不到。
再来看第2条,表述有歧义,
- foreach则不能直接遍历对象里面的属性,这句话中对象里的属性是指单个属性,还是指所有属性?
- 经过对第一条的分析,我们知道foreach可以遍历对象中所有公开的属性,当然public属性是不合理的,这里我们只考虑实现可能性。
- 然后我又尝试了一下,foreach遍历对象中指定的单个属性(public),也没问题,此处可以通过一个public方法获得该属性,从而将属性设置为private。
看一下该博客中给出的示例代码, 实现了Iterator 接口中的5个抽象方法。
class Season implements Iterator{
private $position = 0;//指针指向0
private $arr = array('春','夏','秋','冬');
public function rewind(){
return $this -> position = 0;
}
public function current(){
return $this -> arr[$this -> position];
}
public function key(){
return $this -> position;
}
public function next() {
++$this -> position;
}
public function valid() {
return isset($this -> arr[$this -> position]);
}
}
$obj = new Season;
foreach ($obj as $key => $value) {
echo $key.':'.$value."\n";
}
?>
结果:
0:春
1:夏
2:秋
3:冬
- 看了这个例子,我更迷惑了,实现5个方法,然后遍历一个对象中的一个属性,为什么不知通过一个getAttr方法返回该属性,直接遍历呢?
- 到此,该博客就完了,我的迷惑还未消除,但我注意到了,使用迭代器进行foreach遍历时,并没有显式的调用 Iterator的五个方法。
- 于是刚刚好,看到了另一篇博客 https://blog.csdn.net/luyaran/article/details/82867878,专门讲解迭代器模式的,其中这两句话讲出了foreach遍历对象和使用迭代器遍历对象的区别,
PHP5开始支持了接口, 并且内置了Iterator接口, 所以如果你定义了一个类,并实现了Iterator接口,那么你的这个类对象就是ZEND_ITER_OBJECT,否则就是ZEND_ITER_PLAIN_OBJECT。
对于ZEND_ITER_PLAIN_OBJECT的类,foreach会通过HASH_OF获取该对象的默认属性数组,然后对该数组进行foreach,而对于ZEND_ITER_OBJECT的类对象,则会通过调用对象实现的Iterator接口相关函数来进行foreach。
- 下面这句话是迭代器的定义,字字玑珠, 细细品味
来看下迭代器的定义,那就是提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部显示。它可帮助构造特定的对象,那些对象能够提供单一标准接口循环或迭代任何类型的可计数数据
- 再来看看迭代器内部的五个方法
Iterator::current — Return the current element 返回当前元素
Iterator::key — Return the key of the current element 返回当前元素的键
Iterator::next — Move forward to next element 移向下一个元素
Iterator::rewind — Rewind the Iterator to the first element 重新回到第一个元素
Iterator::valid — Checks if current position is valid 检查当前位置的有效性
- 看过了第一位博主的例子, 下面再看看第二位博主给出的实例
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 $k => $v) {
print "此时键值对 -- key $k: value $v\n\n";
}
在这里,我们向实现迭代器接口的类中传入了一个数组变量,生成了一个对象,专门用来遍历。
我们还可以在类的内部定义一些其他的操作,但从设计模式来讲,最好分开,不要违背单一职责原则,根据场景进行区分。
这样可以向我们的迭代器中传入不同的数组进行遍历,
同时当我们想换一种遍历方式时,只需另外建立一个迭代器,根据需求(比如降序遍历)重新实现5个方法的代码就行了。
数据和算法分离,独立发展
附上第二位博主的总结
来看下迭代器的优点:
1.支持多种遍历方式。比如有序列表,我们根据需要提供正序遍历、倒序遍历两种迭代器。用户只需要得到我们的迭代器,就可以对集合执行遍历操作
2.简化了聚合类。由于引入了迭代器,原有的集合对象不需要自行遍历集合元素了
3.增加新的聚合类和迭代器类很方便,两个维度上可各自独立变化
4.为不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上操作
缺点就是迭代器模式将存储数据和遍历数据的职责分离增加新的集合对象时需要增加对应的迭代器类,类的个数成对增加,在一定程度上增加系统复杂度。
它的使用场景,我们可以参考如下几点:
1.访问一个聚合对象内容而无须暴露它的内部显示
2.需要为聚合对象提供多种遍历方式
3.为遍历不同的聚合结构提供一个统一的接口
最后,咱们来看一个网上找的用迭代器模式来实现的一个斐波那契数列。
我们都知道,斐波那契数列通常做法是用递归实现,当然还有其它的方法,咱们这里用PHP的迭代器来实现一个斐波纳契数列,几乎没有什么难度,只是把类里的next()方法重写了一次。注释已经写到代码中,也是相当好理解的,如下:
class Fibonacci implements Iterator {
private $previous = 1;
private $current = 0;
private $key = 0;
public function current() {
return $this->current;
}
public function key() {
return $this->key;
}
public function next() {
// 关键在这里
// 将当前值保存到 $newprevious
$newprevious = $this->current;
// 将上一个值与当前值的和赋给当前值
$this->current += $this->previous;
// 前一个当前值赋给上一个值
$this->previous = $newprevious;
$this->key++;
}
public function rewind() {
$this->previous = 1;
$this->current = 0;
$this->key = 0;
}
public function valid() {
return true;
}
}
$seq = new Fibonacci;
$i = 0;
foreach ($seq as $f) {
echo "$f ";
if ($i++ === 15) break;
}
输出的结果如下:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610
再次附上原文地址
1:https://www.cnblogs.com/wwjchina/p/7723499.html
2:https://blog.csdn.net/luyaran/article/details/82867878
php迭代器Iterator接口的更多相关文章
- 详解 迭代器 —— Iterator接口、 ListIterator接口 与 并发修改异常
(请关注 本人"Collection集合"博文--<详解 Collection集合>) Iterator接口(迭代器): 概述: 对 collection 进行迭代的迭 ...
- 集合元素的遍历操作,使用迭代器Iterator接口
1.内部的方法:hasNext() 和 next() 推荐的方式: //hasNext():判断是否还有下一个元素while(iterator.hasNext()){ //next():①指针下移 ② ...
- Collections+Iterator 接口 | Map+HashMap+HashTable+TreeMap |
Collections+Iterator 接口 1. Collections 是一个操作 Set.List 和 Map 等集合的工具类 Collections 中提供了大量方法对集合元素进行排序.查询 ...
- java - day011 - 集合, ArrayList HashMap,HashSet, Iterator 接口, for-each 循环格式
集合 ArrayList 丑数: 能被3,5,7整除多次, ArrayList list 接口 | - ArrayList | - Linked ...
- java集合(2)-Collection与Iterator接口
1 package com.j1803.collectionOfIterator; 2 import java.util.ArrayList; 3 import java.util.Collectio ...
- Iterator接口(迭代器)
目录 前言 原理 方法 异常 Iterator接口(迭代器) 前言 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合框架,它是一个对象, ...
- PHP:Iterator(迭代器)接口和生成器
迭代器 可在内部迭代自己的外部迭代器或类的接口.详情:http://php.net/manual/zh/class.iterator.php 接口摘要 Iterator extends Travers ...
- 牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection(List和Set)、集合框架中的Map集合
不多说,直接上干货! 集合框架中包含了大量集合接口.这些接口的实现类和操作它们的算法. 集合容器因为内部的数据结构不同,有多种具体容器. 不断的向上抽取,就形成了集合框架. Map是一次添加一对元素. ...
- Java之Iterator接口(遍历单列集合的迭代器)
Iterator接口概述 在程序开发中,经常需要遍历集合中的所有元素.针对这种需求,JDK专门提供了一个接口java.util.Iterator . Iterator 接口也是Java集合中的一员,但 ...
随机推荐
- WampServer 下载以及安装问题 以及配置远程连接MYSQL
WampServer 3.0 下载: http://dl.pconline.com.cn/download/52877-1.html 碰到的问题DDL无法添加,解决方法:MSVCR110.DLL fo ...
- Hadoop基础之初识大数据与Hadoop
前言 从今天起,我将一步一步的分享大数据相关的知识,其实很多程序员感觉大数据很难学,其实并不是你想象的这样,只要自己想学,还有什么难得呢? 学习Hadoop有一个8020原则,80%都是在不断的配置配 ...
- mysql千万级数据表结构修改
当需要对表进行ddl操作如加索引.增删列时,数据量小时直接在线修改表结构影响不大当表达到百万.千万数据就不能直接在线修改表结构 下面是具体的过程:1.备份数据select * from ih_orde ...
- 转载:深入浅出 Java 8 Lambda 表达式
原文地址:http://viralpatel.net/blogs/Lambda-expressions-java-tutorial/ OneAPM for Java 能够深入到所有 Java 应用内部 ...
- 2. bash基础
通配符 通配符 功能说明 实例 * 匹配所有字符 ls *.o ? 匹配所有的当个字符 ls net??? [a-z] 匹配属于a到z范围集合内的一个字符 ls [a-i]* [...] 与方括号内的 ...
- 修改Mysql 数据库的密码
1.修改my.cnf 在这个文件里面加入 skip-grant-tables 修改之后,保存.然后重启数据库 2.由于我的系统是Centos7 ,数据库是mariadb ,所以执行命令如下: 3.重启 ...
- Linux添加日常任务监控文件或日志大小
1.使用命令"vi/vim xxx.sh"编写shell脚本文件 #!/bin/bash #author yangli # #设置文件检测路径 file_check_path=&q ...
- mybatis resultMap 子元素
resultMap constructor - 类在实例化时,用来注入结果到构造方法中 idArg - ID 参数;标记结果作为 ID 可以帮助提高整体效能 arg - 注入到构造方法的一个普通结果 ...
- 【VS开发】CreateThread给线程函数传递的参数
CreateThread给线程函数传递的参数 HANDLE WINAPI CreateThread ( __in_opt LPSECURITY_ATTRIBUTES lpThreadAttribu ...
- 【VS开发】【计算机视觉】OpenCV读写xml文件《C版本》
一些简单的XML读写操作,记之于笔记以备忘 主要功能: 1. 创建XML 2. 向XML中存储或者是读取Int float型基本数据 3. 通过创建XML元素,存取复杂的结构如:结构体.矩阵 代码如下 ...