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

相關文章
相關標籤/搜索