什么是SPL
spl是standard PHP Library的缩写,它的作用是用于解决典型(常见)问题(common problems)的一组接口与类的集合。
common problem
1,数学建模/数据结构(解决数据的存储问题)
2,元素遍历(解决数据怎么查看的问题)
3,常用方法的统一调用(通用方法数组,集合,自定义遍历)
4,类定义在自动装载(让php程序适应大型项目的管理要求,把功能的实现分散到不同的文件中)
SPL的基本框架
spl的基本框架包括了数据结构,基础接口,基础函数,迭代器,异常,其他。
SPL的常用数据结构
双向链表,堆栈,队列,定长数组,对象容器等等,
双向链表
如果有3个节点。节点1可以访问节点2,节点2可以访问节点3,这就是单向链表。若在单向链表的基础上,节点3可以访问节点2,节点2可以访问节点1,这就形成了双向链表。在链表中,可以通过找到已知节点确定到需要寻找的节点。
双向链表的几个基础概念:
1.bottom : 最先添加到链表中的节点叫做bottom(底部),也称为头部(head)
2.top: 最后添加到链表中的节点叫做top(顶部),也称为尾部
3.链表指针:是一个当前关注的节点标识,可以指向仍以节点
4.当前节点:链表指针指向的节点称为当前节点
在spl中提供了双向链表的的操作类。SplDoublyLinkedList,类下提供的方法有。
- 当前节点操作:rewind、current、next、prev
- 增加节点操作:push、unshift
- 删除节点操作:pop、shift
- 定位操作:bottom、top
- 特定节点操作:offsetExists、offsetGet、offsetSet、offsetUnset
操作事例:
- 链表添加一个数据
$obj = new SplDoublyLinkedList();//实例化双向链表的对象
//print_r($obj);
$obj->push(1);
$obj->push(2);
$obj->push(3);
$obj->unshift(11);
echo'<pre>';
print_r($obj);
结果:
链表的push操作是从右向左将数据推入链表,把新的数据添加到链表的顶部top,unshift操作是将新的数据添加到链表的底部bottom。
- 打印当前节点(注意在未执行rewind方法时,直接调用current此时节点指针没有任何指向,rewind操作用于把节点指针指向bottom所在的节点,current操作用于获取节点指针所指向的节点)
echo 'current:' . $obj->current();
$obj->rewind();
echo 'current:' . $obj->current();
next 方法每调用一次将指针向下移动一位,若移动不存在的下标,则指针指向空地址。 prev方法则是将当前指针向上移动一位。 valid方法操作判断当前节点是否是有效节点,如果是则返回true,反之返回false。 pop方法把top位置的节点从链表中删除,并返回。如果在pop时current正好指向top位置,那么调用pop之后current会失效,指向空地址。 shift操作把bottom位置的节点从链表中删除,并返回。 unshiift操作是把信的节点数据添加到链表底部bottom。
堆栈(先进后出)
继承自SplDoublyLinkedList类的SplStack类。
- push:压入堆栈(存入)
- pop: 退出堆栈(取出)
$stack = new SplStack();
$stack->push('a');//push向堆栈里面放入一个节点到top位置
$stack->push('b');
$stack->push('c');
echo'<pre>';
print_r($stack);
echo 'bottom:' . $stack->bottom() . "\n";
echo 'top:' . $stack->top() . "\n";
//堆栈的offset=0是top所在的位置。与双向链表相反
$stack->offsetSet(0,'C');
print_r($stack);
$stack->rewind();
//双向链表的rewind和堆栈的rewind相反,堆栈的rewind
//使得当前指针所指向top虽在的位置,而双向链表调用之后指向bottom所在位置
echo 'current:' . $stack->current()."\n";
//堆栈的next操作使指针指向靠近bottom位置的下一个节点,而双向链表是靠近
//top的下一个节点
$stack->next();
echo 'current:' . $stack->current()."\n";
//同理
$stack->prev();
echo 'current:' . $stack->current()."\n";
//遍历堆栈
$stack->rewind();
while ($stack->valid()) {
echo $stack->key()."=>".$stack->current()."\n";
$stack->next();//next操作不从链表中删除元素
}
//删除堆栈数据
$popObj = $stack->pop();//pop操作从堆栈里面取出最后一个位置top元素,同时在堆栈中删除该节点。
echo "Poped object:" . $popObj . "\n";
print_r($stack);
队列
- 队列和堆栈刚好相反,先进先出。
- 继承自SplDoublyLinkedList类的SplQueue类
- enqueue: 进入队列
- dequeue: 退出队列
$obj = new SplQueue();
$obj->enqueue('a');//插入一个节点到队列的top位置
$obj->enqueue('b');
$obj->enqueue('c');
echo'<pre>';
print_r($obj);
echo 'bottom:' . $obj->bottom() . "\n";
echo 'top:' . $obj->top() . "\n";
$obj->offsetSet(0,'A');//队列中的offset=0是bottom所在位置,=1是向top方向相邻节点
print_r($obj);
$obj->rewind();//队列中的rewind使指针指向bottom所在位置节点
echo 'current:' . $obj->current()."\n";
while ($obj->valid()) {
echo $obj->key() . "=>" . $obj->current() . "\n";
$obj->next();//next是的当前指针指向top方向的下一个节点
}
//dequeue 操作从队列中提取bottom位置的节点,并返回,同时从队列中删除该元素
echo 'dequeue obj:' . $obj->dequeue() . "\n";
print_r($obj);
SPL的常用迭代器
什么是迭代器
通过某种统一的方式遍历链表或者数组中的元素的过程叫做迭代遍历,而这种统一的遍历工具我们就叫做迭代器。
上面使用的while循环就是默认使用迭代器遍历数据结构中的数据。
PHP中迭代器是通过Iterator接口定义的:
- current()
- key()
- next()
- rewind()
- valid()
ArrayIterator迭代器用于遍历数组,使用foreach和while语句通过ArrayIterator遍历数组的方法,使用seek跳过某些元素的方法,使用ArraryIterator进行排序的方法。
$fruits = [
'apple' => 'apple value',//position = 0
'orange' => 'orange value',//position = 1
'banana' => 'banana value',
'lemon' => 'lemon value',
];
echo'<pre>';
print_r($fruits);
echo '************use fruits directly' . "\n";
foreach ($fruits as $key => $value) {
echo $key . ":" . $value . "\n";
}
//使用ArrayIterator遍历数组
$obj = new ArrayObject($fruits);
$it = $obj->getIterator();
echo '************use ArrayIterator for' . "\n";
foreach ($it as $key => $value) {
echo $key . ":" . $value . "\n";
}
echo '************use ArrayIterator while' . "\n";
$it->rewind();//current调用之前需先调用rewind
while ($it->valid()) {
echo $it->key().':' . $it->current() . "\n";
$it->next();
}
echo '************use ArrayIterator seek' . "\n";
//跳过某些元素进行打印
$it->rewind();
if ($it->valid()) {
$it->seek(1);
while ($it->valid()) {
echo $it->key().':' . $it->current() . "\n";
$it->next();
}
}
echo '************use ArrayIterator ksort' . "\n";
//排序(ksort(对key字典排序) asort(对value字典排序))
$it->ksort();
foreach ($it as $key => $value) {
echo $key . ":" . $value . "\n";
}
AppendIterator能陆续遍历几个迭代器
- 按顺序迭代访问几个不同的迭代器,例如,希望在一次循环中迭代访问两个或者更多的组合。
$arr_a = new ArrayIterator(['a','b','c']);
$arr_b = new ArrayIterator(['d','e','f']);
$it = new AppendIterator();
$it->append($arr_a);
//append方法把迭代器对象添加到AppendIterator对象中
$it->append($arr_b);
foreach ($it as $key => $value) {
echo $value . "\n";
}