摘要:将数组或者集合中的全部或者一部数据取出来,用迭代器比较方便迭代器能陆续遍历几个迭代器按顺序迭代访问几个不同的迭代器。
一、SPL简介
什么是SPL
PHP的标准库SPL:Standard PHP Library
SPL: 用于解决常见普遍问题的一组接口与类的集合
Common Problem:
数学建模/数据结构
解决数据怎么存储的问题
元素遍历
数据怎么查看问题
常用方法的统一调用
通用方法(数组、集合的大小)
自定义遍历
类定义的自动装载
让PHP程序适应大型项目的管理要求,把功能的实现分散到不同的文件中
SPL的基本框架
二、SPL的常用数据结构
2.1 双向链表 2.1.1 双向链表简介
Bottom:最先添加到链表中的节点叫做Bottom(底部),也称为头部(head)
Top:最后添加到链表中得节点叫做top顶部,也称为尾部
链表指针:是一个当前关注的节点的标识,可以指向任意节点
当前指针:链表指针指向的节点称为当前节点
节点名称:可以在链表中唯一标识一个节点的名称,我们通常又称为节点的key或offset
节点数据:存放在链表中的应用数据,通常称为value
/** * 双向链表 */ $obj = new SplDoublyLinkedList(); $obj->push(4); $obj->push(6); $obj->unshift(66); print_r($obj);
SplDoublyLinkedList Object ( [flags:SplDoublyLinkedList:private] => 0 [dllist:SplDoublyLinkedList:private] => Array ( [0] => 66 [1] => 4 [2] => 6 ) )
双向链表常用方法:
Bottom: 获得链表底部(头部)元素,当前指针位置不变
Top: 获取链表顶部(尾部)元素,当前指针位置不变
Push: 往链表顶部(Top)中追加节点
Pop: 把top位置的节点从链表中删除,操作不改变当前指针的位置
Unshif: 往链表底部追加节点(Bottom)
Shif: 删除链表底部的节点
Rewind: 把节点指针指向Bottom所在的节点
Current: 指向链表当前节点的指针,必须在调用之前先调用rewind。当指向的节点被删除之后,会指向一个空节点
Next: 指针指向下一个节点,current的返回值随之改变
Prev: 指针指向上一个节点,current的返回值随之改变
双向链表判断当前节点是否有效节点方法:
if(双向链表对象.current()) 有效 else 无效
或
//用$obj->current()判断当前是否有迭代元素不好,因为当元素值是false,0,或者空字符时 //他们效果和null一样,区分不了,所以严谨的话要使用valid方法判断 if(双向链表对象.valid()) 有效 else 无效2.2 堆栈 2.2.1 堆栈简介
继承自SplDoublyLinkedList类的SplStack类
操作:
- `push`:压入堆栈(存入) - `pop`:退出堆栈(取出)
堆栈:单端出入,先进后出 Fist In Last Out(FILO)
2.2.2 堆栈代码实践/** * 堆栈 */ $obj = new SplStack(); $obj->push(2); $obj->push("test"); $obj->push(6); print_r($obj);
SplStack Object ( [flags:SplDoublyLinkedList:private] => 6 [dllist:SplDoublyLinkedList:private] => Array ( [0] => 2 [1] => test [2] => 6 ) )
常用操作:
Bottom(): 最先进入的元素;
Top(): 最后进入的元素;
offSet(0): 是top的位置
rewind(): 把top的元素置为current()的位置
注意:
- 堆栈的`rewind()`指向`top`,双向链表的`rewind()`指向`bottom` - 堆栈和双向链表都有`next`方法,方向相反2.3 队列
队列和堆栈刚好相反,最先进入队列的元素会最先走出队列
继承自SplDoublyLinkedList类的SqlQueue类
操作:
- `enqueue`:进入队列 - `dequeue`:退出队列
/** * 队列 */ $obj = new SplQueue(); $obj->enqueue("a"); $obj->enqueue("b"); $obj->enqueue("c"); print_r($obj);
SplQueue Object ( [flags:SplDoublyLinkedList:private] => 4 [dllist:SplDoublyLinkedList:private] => Array ( [0] => a [1] => b [2] => c ) )
常用操作:
enqueue: 插入一个节点到队列里面的top位置
dequeue: 操作从队列中提取Bottom位置的节点,同时从队列里面删除该元素
offSet(0): 是Bottom所在的位置
rewind: 操作使得指针指向Bottom所在的位置的节点
next: 操作使得当前指针指向Top方向的下一个节点
通过某种 统一的方式 遍历链表或则数组中的元素的过程叫做迭代遍历,这种统一的遍历工具叫迭代器
PHP中迭代器是通过Iterator接口定义的
3.2 ArrayIterator迭代器ArrayIterator迭代器用于遍历数组
seek(),指针定位到某个位置,很实用,跳过前面n-1的元素
ksort(),对key进行字典序排序
asort(),对值进行字典序排序
$arr=array( "apple" => "apple value", // position = 0 "orange" => "orange value", // position = 1 "grape" => "grape value", "plum" => "plum value" ); $obj=new ArrayObject($arr); $it =$obj->getIterator();//生成数组的迭代器。 foreach ($it as $key => $value){ echo $key . ":". $value ."
"; } echo "
"; //实现和foreach同样功能 $it->rewind();// 调用current之前一定要调用rewind While($it->valid()){//判断当前是否为有效数据 echo $it->key()." : ".$it->current()."
"; $it->next();//千万不能少 } //实现更复杂功能,跳过某些元素进行打印 $it->rewind(); if ($it->valid()){ $it->seek(1);//position,跳过前面 n-1的元素 While($it->valid()){//判断当前是否为有效数据 echo $it->key()." : ".$it->current()."
"; $it->next();//千万不能少 } } $it->ksort();//对key进行字典序排序 //$it->asort();//对值进行字典序排序 foreach ($it as $key => $value){ echo $key . ":". $value ."
"; }
foreach本质会自动生成一个迭代器,只是使用了迭代器的最长用功能,如果要实现复杂需求,foreach实现不了,就需要手动生成迭代器对象来使用了
比如,要从一个大数组中取出一部分数据,foreach比较困难,除非他知道数据的样子。将数组或者集合中的全部或者一部数据取出来,用迭代器比较方便
AppendIterator能陆续遍历几个迭代器
按顺序迭代访问几个不同的迭代器。例如,希望在一次循环中迭代访问两个或者更多的组合
$arr_a = new ArrayIterator(array("a"=> array("a","b"=>234),"b","c")); $arr_b = new ArrayIterator(array("d","e","f")); $it = new AppendIterator(); $it->append($arr_a);//追加数组 $it->append($arr_b);//追加数组,然后遍历$it foreach ($it as $key => $value){ print_r($value); }3.4 MultipleIterator迭代器
用于把多个Iterator里面的数据组合成为一个整体来访问
Multipleiterator将多个arrayiterator拼凑起来
Appenditerator将多个arrayiteratorr连接起来
$idIter = new ArrayIterator(array("01","02","03")); $nameIter = new ArrayIterator(array("张三","李四","王五")); $ageIter = new ArrayIterator(array("22","23","25")); $mit = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);//按照key关联 $mit->attachIterator($idIter,"ID"); $mit->attachIterator($nameIter,"NAME"); $mit->attachIterator($ageIter,"AGE"); foreach ($mit as $value){ print_r($value); }
Array ( [ID] => 01 [NAME] => 张三 [AGE] => 22 ) Array ( [ID] => 02 [NAME] => 李四 [AGE] => 23 ) Array ( [ID] => 03 [NAME] => 王五 [AGE] => 25 )四、SPL的基础接口 4.1 最常用的接口
Countable:继承了该接口的类可以直接调用count(),得到元素个数
OuterIterator:,如果想对迭代器进行一定的处理之后再返回,可以用这个接口,相当于进行了一次封装,对原来的进行一定的处理
RecursiveIterator:,可以对多层结构的迭代器进行迭代,比如遍历一棵树,类似于filesystemIterator
SeekableIterator:,可以通过seek方法定位到集合里面的某个特定元素
4.2 Countable在代码里面经常可以直接用count($obj)方法获取对象里面的元素个数
count(array("name"=>"Peter","id"=>"5"));
对于我们定义的类,也能这样访问吗?
如果对象本身也有count函数,但是没有继承countable接口,直接用count函数时,不会调用对象自定义的count
如果对象本身也有count函数,同时对象也继承了countable接口,直接用count函数时,会调用对象自身的count函数,效果相当与:对象->count()
count()是Countable必须实现的接口
count(Countable $obj)返回是类内部的count()返回的结果,其会被强制转成int
$arr = array( array("name" => "name value", "id" => 2), array("name" => "Peter", "id" => 4, "age" => 22), ); echo count($arr); echo count($arr[1]); class CountMe implements Countable { protected $myCount = 6; protected $myCount2 = 3; protected $myCount3 = 2; public function count() { // TODO: Implement count() method. return $this->myCount; } } $obj = new CountMe(); echo count($obj); //64.3 OuterIterator
OuterIterator接口
如果想对迭代器进行一定得处理湖再返回,可以用这个接口
IteratorIterator类是OuterIterator的实现,扩展的时候,可以直接继承IteratorIterator
$array = ["Value1","Value2","Value3","Value4"]; $outerObj = new OuterImpl(new ArrayIterator($array)); foreach ($outerObj as $key => $value){ echo "++".$key."-".$value." "; } class OuterImpl extends IteratorIterator { public function current() { return parent::current()."_tail"; } public function key() { return "Pre_".parent::key(); } }
++Pre_0-Value1_tail ++Pre_1-Value2_tail ++Pre_2-Value3_tail ++Pre_3-Value4_tail4.4 RecursiveIterator和SeekableIterator
完!
参考教程:站在巨人的肩膀上写代码—SPL
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/28632.html
摘要:什么是是标准库的缩写。根据官方定义,它是是用于解决典型问题的一组接口与类的集合。而的对象则严格以堆栈的形式描述数据,并提供对应的方法。返回所有已注册的函数。 什么是SPL SPL是Standard PHP Library(PHP标准库)的缩写。 根据官方定义,它是a collection of interfaces and classes that are meant to solve...
摘要:我把分为五个部分,,,,而其中是就是做一些类的介绍与相关的类在各自文章内,在介绍这些类之前,先介绍几个接口数组式访问接口只要实现了这个接口,就可以使得像那样操作。只有内部的类用写的类才可以直接实现接口代码中使用或接口来实现遍历。 我把SPL分为五个部分:Iterator,Classes,Exceptions,Datastructures,Function;而其中classes是就是做一...
摘要:中在基础集合类路由类中和分页类中等,都用到了对象遍历这个小知识点,这些类都是实现了这个接口,这个接口定义,返回的是迭代器对象。标准扩展库中提供了很多默认迭代器实现类,比较常用的是数组迭代器对象,参考官网迭代器。 说明:本文章主要讲述PHP的对象遍历(Iterator)知识点。由于Laravel框架中就在集合(Collection)中用到了对象遍历知识点,故记录并学习之。同时,作者会将开...
摘要:也就是闲时为了写文章而写的一篇关于源码的阅读笔记。是标准库的缩写,一组旨在解决标准问题的接口和类的集合。提供了一套标准的数据结构,一组遍历对象的迭代器,一组接口,一组标准的异常,一系列用于处理文件的类,提供了一组函数,具体可以查看文档。 也就是闲时为了写文章而写的一篇关于 Pimple 源码的阅读笔记。Pimple 代码有两种编码方式,一种是以 PHP 编写的,另一种是以 C 扩展编写...
摘要:由于没有方法,所以就不能用重置游标,这个时候已经到最后了,所以为空一种占位符形式的迭代器,不执行任何操作。检查是否含有子节点输出所有字节点将一个树形结构的迭代器展开为一维结构。 Iterator界面 本段内容来自阮一峰老师再加自己的部分注解 SPL规定,所有部署了Iterator界面的class,都可以用在foreach Loop中。Iterator界面中包含5个必须部署的方法: * ...
阅读 3527·2021-11-08 13:15
阅读 2081·2019-08-30 14:20
阅读 1342·2019-08-28 18:08
阅读 961·2019-08-28 17:51
阅读 1458·2019-08-26 18:26
阅读 2974·2019-08-26 13:56
阅读 1452·2019-08-26 11:46
阅读 2568·2019-08-23 14:22