热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PHP标准库SPL学习之数据结构、常用迭代器、基础接口

一、SPL简介什么是SPLPHP的标准库SPL:StandardPHPLibrarySPL:用于解决常见普遍问题的一组接口与类的集合CommonProblem
一、SPL简介

     什么是SPL

  • PHP的标准库SPL:Standard PHP Library

     SPL: 用于解决常见普遍问题的一组接口与类的集合

     Common Problem:

  1. 数学建模/数据结构

    • 解决数据怎么存储的问题
  2. 元素遍历

    • 数据怎么查看问题
  3. 常用方法的统一调用

    • 通用方法(数组、集合的大小)
    • 自定义遍历
  4. 类定义的自动装载

    • 让PHP程序适应大型项目的管理要求,把功能的实现分散到不同的文件中

     SPL的基本框架

     clipboard.png

二、SPL的常用数据结构

     clipboard.png

2.1 双向链表

2.1.1 双向链表简介

     clipboard.png

     Bottom:最先添加到链表中的节点叫做Bottom(底部),也称为头部(head)
     Top:最后添加到链表中得节点叫做top顶部,也称为尾部
     链表指针:是一个当前关注的节点的标识,可以指向任意节点
     当前指针:链表指针指向的节点称为当前节点
     节点名称:可以在链表中唯一标识一个节点的名称,我们通常又称为节点的keyoffset
     节点数据:存放在链表中的应用数据,通常称为value

2.1.2 双向链表代码实践

/*** 双向链表*/
$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方向的下一个节点

三、SPL的常用迭代器

3.1 迭代器概述

通过某种 统一的方式 遍历链表或则数组中的元素的过程叫做迭代遍历,这种统一的遍历工具叫迭代器

     PHP中迭代器是通过Iterator接口定义的

clipboard.png

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比较困难,除非他知道数据的样子。将数组或者集合中的全部或者一部数据取出来,用迭代器比较方便

3.3 AppendIterator迭代器

     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'));

     对于我们定义的类,也能这样访问吗?

  1. 如果对象本身也有count函数,但是没有继承countable接口,直接用count函数时,不会调用对象自定义的count
  2. 如果对象本身也有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); //6

4.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."\n";
}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_tail

4.4 RecursiveIterator和SeekableIterator

     clipboard.png

     clipboard.png

完!

参考教程:站在巨人的肩膀上写代码—SPL



推荐阅读
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了Python对Excel文件的读取方法,包括模块的安装和使用。通过安装xlrd、xlwt、xlutils、pyExcelerator等模块,可以实现对Excel文件的读取和处理。具体的读取方法包括打开excel文件、抓取所有sheet的名称、定位到指定的表单等。本文提供了两种定位表单的方式,并给出了相应的代码示例。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 如何在php中将mysql查询结果赋值给变量
    本文介绍了在php中将mysql查询结果赋值给变量的方法,包括从mysql表中查询count(学号)并赋值给一个变量,以及如何将sql中查询单条结果赋值给php页面的一个变量。同时还讨论了php调用mysql查询结果到变量的方法,并提供了示例代码。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
author-avatar
萝莉莲籽芯
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有