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

1、SPL简介

     什么是SPLphp

  • PHP的标准库SPL:Standard PHP Library

     SPL: 用于解决常见广泛问题的一组接口与类的集合数组

     Common Problem:数据结构

  1. 数学建模/数据结构app

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

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

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

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

     SPL的基本框架this

     clipboard.png

2、SPL的经常使用数据结构

     clipboard.png

2.1 双向链表

2.1.1 双向链表简介

     clipboard.png

     Bottom:最早添加到链表中的节点叫作Bottom(底部),也称为头部(head)
     Top:最后添加到链表中得节点叫作top顶部,也称为尾部
     链表指针:是一个当前关注的节点的标识,能够指向任意节点
     当前指针:链表指针指向的节点称为当前节点
     节点名称:能够在链表中惟一标识一个节点的名称,咱们一般又称为节点的keyoffset
     节点数据:存放在链表中的应用数据,一般称为valuespa

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的返回值随之改变3d

     双向链表判断当前节点是否有效节点方法:

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方向的下一个节点

3、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 .'<br />';
}

echo '<br />';
//实现和foreach一样功能
$it->rewind();// 调用current以前必定要调用rewind
While($it->valid()){//判断当前是否为有效数据
    echo $it->key().' : '.$it->current().'<br />';
    $it->next();//千万不能少
}

//实现更复杂功能,跳过某些元素进行打印
$it->rewind();
if ($it->valid()){
    $it->seek(1);//position,跳过前面 n-1的元素
    While($it->valid()){//判断当前是否为有效数据
        echo $it->key().' : '.$it->current().'<br />';
        $it->next();//千万不能少
    }
}

$it->ksort();//对key进行字典序排序
//$it->asort();//对值进行字典序排序
foreach ($it as $key => $value){
    echo $key . ":". $value .'<br />';
}

     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
)

4、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

相关文章
相关标签/搜索