当前位置: 首页 > 后端技术 > PHP

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

时间:2023-03-29 14:08:21 PHP

一、SPL简介什么是SPLPPHP的标准库SPL:标准PHP库SPL:用于解决常见常见问题的接口和类的集合CommonProblem:数学建模/数据结构解决数据如何存储问题元素遍历数据如何查看问题常用方法统一调用常用方法(数组、集合大小)自定义遍历类定义自动加载使PHP程序适应大型项目的管理需求,将功能的实现分散到不同的文件中SPL的基本框架2.SPL的常用数据结构2.1双向链表2.1.1双向链表简介Bottom:加入链表的第一个节点称为Bottom(底部),也称为表头(head)Top:加入链表的节点称为表顶top,也称为尾表链表指针:当前关注的节点的标识,可以指向任意一个节点Currentpointer:链表指针指向的节点称为当前节点Nodename:链表中能唯一标识一个节点的名称,我们通常称其为节点的key或offset节点数据:链表中存储的应用数据,通常称为value2.1.2双向链表代码实践/***双向链表*/$obj=newSplDoublyLinkedList();$obj->push(4);$obj->push(6);$obj->unshift(66);print_r($obj);SplDoublyLinkedListObject([flags:SplDoublyLinkedList:private]=>0[dllist:SplDoublyLinkedList:private]=>Array([0]=>66[1]=>4[2]=>6))双向链表常用方法:bottom:获取链表的最底(头)元素,当前指针位置不变Top:获取链表的顶部(tail)元素,当前指针位置不变Push:向链表顶部(Top)添加节点pop:从链表中删除顶部位置的节点,该操作不改变当前指针位置unshif:在链表底部添加一个节点(Bottom)Shif:删除链表底部的节点rewind:将节点指针指向Bottom所在节点Current:指向链表当前节点的指针,调用前必须调用rewind当指向的节点被删除时,会指向一个空节点Next:指针指向下一个节点,current的返回值随之变化。Prev:指针指向上一个节点,current的返回值随之变化。双向链表判断当前节点是否有效节点方法:if(双向链表object.current())validelseinvalid或者//用$obj->current()判断当前是否有可迭代元素是不好,因为当元素值为false,0,或者null字符时//它们的作用和null是一样的,无法区分,所以如果严格的话,必须用valid方法判断if(双联listobject.valid())validelseinvalid`:入栈(store)-`pop`:出栈(takeout)Stack:单端入,先入后出FistInLastOut(FILO)2.2.2堆栈代码实践/***stack*/$obj=newSplStack();$obj->push(2);$obj->push('test');$obj->push(6);print_r($obj);SplStack对象([flags:SplDoublyLinkedList:private]=>6[dllist:SplDoublyLinkedList:private]=>Array([0]=>2[1]=>test[2]=>6))Common操作:Bottom():第一个进入的元素;Top():最后输入的元素;offSet(0):是top的位置rewind():把栈顶的元素设置到current()的位置注意:-栈的`rewind()`指向`top`,双向链表的`rewind()`指向`bottom`——栈和双向链表都有一个`next`方法,方向相反2.3Queues队列和栈刚好相反,第一个进入队列的元素将最先离开队列SqlQueue类继承自SplDoublyLinkedList类操作:-`enqueue`:进入队列-`dequeue`:退出队列/***queue*/$obj=新的SplQueue();$obj->enqueue('a');$obj->enqueue('b');$obj->enqueue('c');print_r($obj);SplQueueObject([flags:SplDoublyLinkedList:private]=>4[dllist:SplDoublyLinkedList:private]=>Array([0]=>a[1]=>b[2]=>c))常用操作:入队:插入一个节点到队列的最前面位置出队:operation从队列中取出Bottom位置的节点,同时删除队列中的元素offSet(0):为Bottom位置rewind:操作使指针指向nextBottom位置的节点:该操作使当前指针指向Top方向的下一个节点3.SPL常用迭代器3.1迭代器概述以统一方式遍历链表或数组中元素的过程称为迭代遍历。这种统一的遍历工具称为迭代器。PHP中的迭代器是通过Iterator接口定义的。3.2ArrayIteratorIteratorArrayIterator迭代器用于遍历数组seek(),指针定位到某个位置,非常实用,跳过前面n-1个元素ksort(),按字典序对keys进行排序asort(),然后按字典顺序对值进行排序$arr=array('apple'=>'applevalue',//position=0'orange'=>'orangevalue',//position=1'grape'=>'葡萄价值','李子'=>吨;'plumvalue');$obj=newArrayObject($arr);$it=$obj->getIterator();//生成数组迭代器foreach($itas$key=>$value){echo$key.“:”。$value.'
';}echo'
';//实现和foreach一样的功能$it->rewind();//一定要在调用current之前调用rewindWhile($it->valid()){//判断当前数据是否有效echo$it->key().':'.$it->current().'
';$it->next();//一定不能少}//实现更复杂的功能,跳过一些元素进行打印$it->rewind();if($it->valid()){$it->seek(1);//位置,跳过前面的n-1个元素while($it->valid()){//判断当前数据是否有效echo$it->key().':'.$it->current().'
';$it->next();//一定不能少}}$it->ksort();//按字典顺序对keys进行排序//$it->asort();//对中的values进行排序字典序foreach($itas$key=>$value){echo$key.“:”。$value.'
';}foreach的本质是会自动生成一个迭代器,只是使用了迭代器的最长函数。如果要实现复杂的需求而foreach无法实现,则需要手动生成迭代器对象来使用。例如,foreach很难从一个大数组中提取部分数据。除非他知道数据是什么样子的。使用迭代器取出数组或集合中的全部或部分数据会更方便。例如,您想在一个循环中迭代两个或多个组合$arr_a=newArrayIterator(array('a'=>array('a','b'=>234),'b','c'));$arr_b=newArrayIterator(array('d','e','f'));$it=newAppendIterator();$it->append($arr_a);//追加数组$it->append($arr_b);//追加数组,然后遍历$itforeach($itas$key=>$value){print_r($value);}3.4MultipleIteratorIterator用于将多个Iterator中的数据组合成Awhole访问Multipleiterator拼凑多个数组迭代器Appenditerator连接多个数组迭代器$idIter=newArrayIterator(array('01','02','03'));$nameIter=newArrayIterator(array('张三','李四','王舞'));$ageIter=newArrayIterator(array('22','23','25'));$mit=newMultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);//根据key关联$mit->attachIterator($idIter,"ID");$mit->attachIterator($nameIter,"NAME");$mit->attachIterator($ageIter,"AGE");foreach($mitas$value){打印_r($值);}Array([ID]=>01[NAME]=>张三[AGE]=>22)Array([ID]=>02[NAME]=>李四[AGE]=>23)Array([ID]=>03[NAME]=>WangWu[AGE]=>25)四、SPL的基本接口4.1最常用的接口Countable:继承该接口的类可以直接调用count()获取元素个数OuterIterator:,如果你想对迭代器进行一定的处理并返回后,就可以使用这个接口,相当于对原来的RecursiveIterator:进行了封装,进行了一定的处理,可以对多层结构的迭代器进行迭代,比如作为遍历一棵树,类似于filesystemIteratorSeekableIterator:,可以使用seek方法定位集合中的特定元素4.2Countable代码中,往往可以直接使用count($obj)方法获取集合中的元素个数对象计数(数组('name'=>'Peter','id'=>'5'));对于我们定义的类,是不是也可以这样访问呢?如果对象本身也有count函数,但是没有继承countable接口,直接使用count函数时,不会调用对象的自定义count。如果对象本身也有count函数,并且对象也继承了countable接口,当直接使用count函数时,会调用对象本身的count函数,效果相同:object->count()count()是Countable必须实现的接口。$arr=array(array('name'=>'namevalue','id'=>2),array('name'=>'Peter','id'=>4,'age'=>22),);echocount($arr);echocount($arr[1]);类CountMe实现Countable{protected$myCount=6;保护$myCount2=3;保护$myCount3=2;publicfunctioncount(){//TODO:实现count()方法.return$this->myCount;}}$obj=newCountMe();回声计数($obj);//64.3OuterIteratorOuterIterator接口如果你想处理迭代器并返回它,你可以使用这个接口IteratorIterator类是OuterIterator的实现。扩展时可以直接继承IteratorIterator$array=['Value1','Value2','Value3','Value4'];$outerObj=newOuterImpl(newArrayIterator($array));foreach($outerObjas$key=>$value){echo"++".$key.'-'.$value."\n";}classOuterImplextendsIteratorIterator{publicfunctioncurrent(){returnparent::current()."_tail";}publicfunctionkey(){return"Pre_".parent::key();}}++Pre_0-Value1_tail++Pre_1-Value2_tail++Pre_2-Value3_tail++Pre_3-Value4_tail4.4RecursiveIterator和SeekableIterator完成!参考教程:站在巨人的肩膀上写代码——SPL