lterator 迭代器|学习笔记

简介: 快速学习 lterator 迭代器

开发者学堂课程【PHP 进阶教程-由浅入深掌握面向对象开发-第二阶段:lterator 迭代器】学习笔记,与课程紧密联系,让用户快速学习知识。  

课程地址:https://developer.aliyun.com/learning/course/712/detail/12716


lterator 迭代器


内容介绍:

一、目标

二、概念

三、步骤

四、示例

五、小结


一、目标

目标∶理解 lterator 迭代器与 foreach 的关系,掌握迭代器的工作原理,实现自主控制迭代器

三、foreach 对于对象的遍历完全受制于访问修饰限定符,我们无法控制 foreach 遍历对象时是怎样实现遍历的,但是如果想要控制,lterator 迭代器能够帮助我们实现对 foreach 不管是内外都可以进行的限定。


二、概念

lterator 迭代器: PHP 内置的一种能够修改 foreach 内部运行机制的接口

·1.lterator 迭代器内置了5个抽象方法,实现迭代器的类必须实现5个抽象方法。只要类实现了 lterator 迭代器,就意味着对这个类的对象进行遍历的时候可以自己控制。

2.实现了 lterator 迭代器的类的对象在进行 foreach 时,不会按照 foreach 原来的机制处理,而是调用迭代器的5个方法

3.foreach 本身的执行步骤

初始化目标:将对象指针指向第一个属性(执行一次)

②判定指针是否有效:判定当前指针指向的元素是否存在,存在下一步,不存在终止(N+1次执行,有 N 个数据,最简单的1次是没有数据要遍历)

③取出当期指针元素下标(属性名)︰将当前属性的名字取出来存储到变量( N 次执行)

④取出当前指针元素值(属性值)︰将当前属性的值取出来存储到变量( N 次执行)

③④理论上是一步,键值对是取出元素把键复制给键变量)

⑤将指针指向下一个:将取出元素后的指针指向下一个属性( N 次执行)

五、4.lterator 迭代器的本质就是改变 foreach 内部的5个方式,实现开发者的自定义控制


三、步骤

1、当前类的对象存在遍历需求

2、当前遍历的方式需要自定义控制

3、当前类实现 lterator 迭代器,并实现对应5个方法

4、遍历对象


四、示例

1.简单迭代控制(针对索引|数组)

索引数组是指在类里有私有属性,希望遍历对象时把属性里面的值给遍历出来,而不是遍历公有属性。

current:获取当前数组指针所指向的元素值

key:与当前指针元素所指向的元素的下标

next:将当前元素的指针下移一位

rewind:让当前数组的指针指向第一个元素

valid:判定当前指针的有效性

这五个方法对应 foreach 的五个步骤。

class Person implements Iterator{

#属性列表(索引数组

private $properties = [ 'name ' , 'age ' , ' gender ' , ' height ' , ' weight'];

#下标属性

private $key = 0;

#实现5个方法

public function current(){

#取出当前数组元素值

return $this->properties[$this->key] ;

}

public function key(){

#返回当前下标

return $this->key;

}

public function next(){

#不需要返回值:当前下标+1

$this->key++;

}

public function rewind(){

#不需要返回值:重置数组下标

$this->key = 0;

}

public function valid(){

#需要返回布尔值:判定下标对应的元素是否存在即可

return isset($this->properties[$this->key]);

}

}

定义下标属性叫做 key,原始下标等于零。现在想要遍历属性里的元素,current 方法要获取当前数组元素当前指针位置的元素值,当前元素值即为下标0,所以只要把数组属性取出来,然后再把当前的下标给它就可以了。key 是获取当前指针,只需要把这个返回给外面就可以。next 要做的是 key++rewind 让下标为0,不需要返回值。valid 是判定当前指针是否有效,判定的方式有很多种,此处 isset 是把下标给你去取,看能不能取到这个值,就可以判定是否有这个下标。

先不考虑实现接口,只有一个类。我希望对私有属性进行遍历,还建了一个属性用来保存下标。

图片1.png

图片2.png

然后进行实例化

$p = new Person();

foreach($p as $k =>$v){

echo $k . ' : ' . $v . '
';

}

图片3.png

效果是遍历不出来任何东西,是因为正常 foreach 遍历是遍历公有属性,但是此处没有公有属性。我们定义的方法也没有改变 foreach 的原理,foreach 还是按照原来的逻辑运行,但是此时如果添加了 implements Iterator,如果没有实现它的方法,系统依然会报错,系统会显示 person 有五个方法必须要实现,做完五个方法后系统就不会报错,即便是不进行 foreach。此时再进行 foreach 会发现输出了数组的下标值,此时就实现了控制。

添加 echo__METHOD__,'
';
可以看出方法被运行以及运行了多少次

图片4.png

图片5.png

第一个走的 person 的 rewind,首先第一个 foreach 是重置数组指针,第二步判定是否有效,有效之后取出当前值和当前下标,再指针下移,下移之后又进行 valid,rewind 只进行一次,valid 进行六次,一共有五个元素,所以 valid 是 N+1个,而其他的都只有对应的数组元素个数。这样就实现了想要控制的对象遍历方式,但是此时访问的只是索引数组。索引针对的是简单数组,能够通过下标控制,但是如果下标是指定的而且不是连续的,就不能使用这种方式。所以我们应用一种针对全部数组的复杂形式

2.复杂迭代控制(针对全部数组)

class Person implements Iterator{

private $info = [

' name' =>'',

'age'=>5,

'gender'-> '',

' height'=> 0,

'weight'=> 0

];

#实现5个方法

public function current(){

#返回当前元素当前的值:当前元素是一个数组,那就可以使用数组函数 current 来处理 return current($this->info);

}

public function key(){

#当前方法不需要返回值:说明外部调用的时候不会用到返回值

next($this->info);

}

public function rewind(){

#也不需要返回值

reset($this->info);

}

public function valid(){

# 需要返回布尔值:而且没有直接的函数能够判定:可以通过 key 取出当前指针元素的下标,然后再通过这个下标去判定元素是否存在(因为 false 不能成为数组元素下标,系统会自动转换成0)

return isset($this->info[key($this->info)]);

}

}

此时它的实现方式 current,数组会用数组函数 current 来获取当前数组指针所对应的值,这个时候不去控制而是交给函数来控制。current 取出当前数组的值,key 函数取出当前数组的下标,next 函数让数组指针下移,rewind 调用 reset 函数重置数组指针,所以数组下标关联还是索引,连不联续都不重要。valid 判定需要返回一个布尔值,而且没有直接的函数去判定是否有效,所以一般是通过 key

把当前数据组的指针取出来,再看对应的数组有没有下标。

图片6.png

此时是一样的效果。前一种方式如果索引不连续马上就会报错,因为是从0每次加一,如果不连续就意味着下一个元素就会出错,current 因为下标没有对应的元素而取不到值,但是第二种方法就针对所有的数组,核心是数组里的函数,valid 需要判断取出来的下标,false 不能成为下标元素,所以判定有没有叫 false 的下标,如果没有就返回一个 false,其他的都可以有所以都返回 true。这就是本次遍历的核心,但是最终的本质是因为 lterator 迭代器的五个方法存在,而 foreach 在遍历时自动检测对象实现了迭代器而且有五个方法,所以 foreach 本来的逻辑就变成调用 current、key、next、rewindvalid 来实现。


五、小结

1、lterator 迭代器是专门针对有遍历对象控制的类的而存在的

2、迭代器能够有效控制 foreach 对对象的遍历,从而保护好内部的结构,自主控制要遍历的内容。而且本身是从内部操作,所以这种遍历可以完全控制它的逻辑和安全性这就是 lterator 迭代器的存在价值。

相关文章
|
3月前
|
C++ 容器
【C/C++笔记】迭代器
【C/C++笔记】迭代器
25 1
|
3月前
|
存储 安全 程序员
【C/C++笔记】迭代器范围
【C/C++笔记】迭代器范围
66 0
|
6月前
|
算法 程序员 C语言
【C++ 迭代器实现细节 】深入探索C++迭代器:从实现到整合
【C++ 迭代器实现细节 】深入探索C++迭代器:从实现到整合
165 0
|
6月前
|
C++ 容器
C++:迭代器
C++:迭代器
70 0
|
6月前
|
算法 C++ 容器
c++迭代器介绍
C++中的迭代器是一种抽象的数据访问对象,它允许对容器中的元素进行遍历,而不必暴露底层数据结构的细节。迭代器提供了一种通用的方法来访问容器中的元素,无论容器的类型是什么。C++标准库中的许多容器(如vector、list、map等)都支持迭代器。
78 0
|
设计模式 开发框架 .NET
C#——迭代器
C#——迭代器
83 0
C#——迭代器
|
设计模式 JavaScript 前端开发
我学会了,前端迭代器
设计思路: 要有一个待迭代的数据对象,存放原始数据。 要有一个对迭代器行为进行封装的class,在这个class中可以定义遍历对象的一些行为。 要有一个获取指定数据对象迭代器操作类,在这个操作类中就直接拿到指定的迭代器。当然你在初始化的时候你可以传入待迭代的数据对象,也可以在操作类中追加待迭代的数据对象的子项。
211 0
我学会了,前端迭代器
|
Python
Python编程:iterator迭代器
Python编程:iterator迭代器
119 0
|
设计模式 Java
每天一个知识点(九)你知道迭代器 Iterator 是什么吗?
迭代器模式是二十三种设计模式之一,这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。 在Java中,通过iterator.hasNext()检测是否存在下一条记录,通过iterator.next遍历集合中的元素。