SPL是Standard PHP Library(PHP標準庫)的縮寫。php
The Standard PHP Library (SPL) is a collection of interfaces and classes that are meant to solve common problems.
官網說,SPL是用來解決典型問題(common problems)的一組接口與類的集合。html
那麼,什麼是common problems呢?node
- 數據結構 解決數據怎麼存儲問題 - 元素遍歷 數據怎麼查看 - 經常使用方法的統一調用 數組、集合大小 自定義遍歷 - 類自動加載 spl_autoload_register
包含哪些內容?編程
SPL規定,全部實現了Iterator接口的class,均可以用在foreach Loop中。Iterator接口中包含5個必須實現的方法:數組
interface Iterator extends Traversable{ //返回當前元素 public mixed current ( void ); //返回當前元素的鍵 public scalar key ( void ); //向前移動到下一個元素 public void next ( void ); //返回到迭代器的第一個元素 public void rewind ( void ); //檢查當前位置是否有效 public boolean valid ( void ); }
實現ArrayAccess接口,可使得object像array那樣操做。ArrayAccess接口包含四個必須實現的方法:網絡
interface ArrayAccess { //檢查一個偏移位置是否存在 public mixed offsetExists ( mixed $offset ); //獲取一個偏移位置的值 public mixed offsetGet( mixed $offset ); //設置一個偏移位置的值 public mixed offsetSet ( mixed $offset ); //復位一個偏移位置的值 public mixed offsetUnset ( mixed $offset ); }
假設對象A實現了上面的ArrayAccess接口,這時候雖然能夠像數組那樣操做,卻沒法使用foreach遍歷,除非實現了前面提到的Iterator接口。數據結構
另外一個解決方法是,有時會須要將數據和遍歷部分分開,這時就能夠實現IteratorAggregate接口。它規定了一個getIterator()
方法,返回一個使用Iterator接口的object。koa
IteratorAggregate extends Traversable { /* 獲取一個外部迭代器 */ abstract public Traversable getIterator ( void ) }
示例:函數
<?php class myData implements IteratorAggregate { public $property1 = "Public property one"; public $property2 = "Public property two"; public $property3 = "Public property three"; public function __construct() { $this->property4 = "last property"; } public function getIterator() { return new ArrayIterator($this); } } $obj = new myData; foreach($obj as $key => $value) { var_dump($key, $value); echo "\n"; } ?>
注意:
雖然都繼承自Traversable
,但這是一個沒法在 PHP 腳本中實現的內部引擎接口。咱們直接使用IteratorAggregate
或 Iterator
接口來代替它。oop
這個接口用於遍歷多層數據,它繼承了Iterator接口,於是也具備標準的current()、key()、next()、 rewind()和valid()方法。同時,它本身還規定了getChildren()
和hasChildren()
方法。The getChildren()
method must return an object that implements RecursiveIterator。
SeekableIterator接口也是Iterator接口的延伸,除了Iterator的5個方法之外,還規定了seek()
方法,參數是元素的位置,返回該元素。若是該位置不存在,則拋出OutOfBoundsException。
這個接口規定了一個count()
方法,返回結果集的數量。
數據結構是計算機存儲、組織數據的方式。
SPL提供了雙向鏈表、堆棧、隊列、堆、降序堆、升序堆、優先級隊列、定長數組、對象容器。
基本概念
Bottom:節點,第一個節點稱Bottom;
Top:最後添加的鏈表的節點稱Top;
當前節點(Current):鏈表指針指向的節點稱爲當前節點;
SplDoublyLinkedList 實現了Iterator
, ArrayAccess
, Countable
接口。
類摘要
SplDoublyLinkedList implements Iterator , ArrayAccess , Countable { /* 方法 */ public __construct ( void ) public void add ( mixed $index , mixed $newval ) public mixed bottom ( void ) public int count ( void ) public mixed current ( void ) public int getIteratorMode ( void ) public bool isEmpty ( void ) public mixed key ( void ) public void next ( void ) public bool offsetExists ( mixed $index ) public mixed offsetGet ( mixed $index ) public void offsetSet ( mixed $index , mixed $newval ) public void offsetUnset ( mixed $index ) public mixed pop ( void ) public void prev ( void ) public void push ( mixed $value ) public void rewind ( void ) public string serialize ( void ) public void setIteratorMode ( int $mode ) public mixed shift ( void ) public mixed top ( void ) public void unserialize ( string $serialized ) public void unshift ( mixed $value ) public bool valid ( void ) }
注意:SplDoublyLinkedList::setIteratorMode
用來設置鏈表模式:
迭代方向:
SplDoublyLinkedList::IT_MODE_LIFO (Stack style)
SplDoublyLinkedList::IT_MODE_FIFO (Queue style)
迭代器行爲:
SplDoublyLinkedList::IT_MODE_DELETE (Elements are deleted by the iterator)
SplDoublyLinkedList::IT_MODE_KEEP (Elements are traversed by the iterator)
默認模式: SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_KEEP
當前節點操做:
rewind:將鏈表的當前指針指向第一個元素
current:鏈表當前指針,當節點被刪除後,會指向空節點
prev:上一個
next:下一個
增長節點操做:
push 在雙向鏈表的結尾處將元素壓入
unshift 前置雙鏈表元素,預備值在雙鏈表的開始
刪除節點操做:
pop 從雙向鏈表的結尾彈出一個節點,不會改變指針位置
shift從雙向鏈表的開頭彈出一個節點,不會改變指針位置
定位操做:
bottom 返回當前雙向鏈表的第一個節點的值,當前指針不變
top返回當前雙向鏈表的最後一個節點的值,當前指針不變
特定節點操做:
offsetExists 理解爲key是否存在
offsetGet將key節點拿出來
offsetSet把數據刷新
offsetUnset刪除
示例:SplDoublyLinkedList.php
<?php /** *SplDoublyLinkedList 類學習 */ $obj = new SplDoublyLinkedList(); $obj -> push(1);//把新的節點添加到鏈表的頂部top $obj -> push(2); $obj -> push(3); $obj -> unshift(10);//把新節點添加到鏈表底部bottom print_r($obj); $obj ->rewind();//rewind操做用於把節點指針指向Bottom所在節點 $obj -> prev();//使指針指向上一個節點,靠近Bottom方向 echo 'next node :'.$obj->current().PHP_EOL; $obj -> next(); $obj -> next(); echo 'next node :'.$obj->current().PHP_EOL; $obj -> next(); if($obj -> current()) echo 'current node valid'.PHP_EOL; else echo 'current node invalid'.PHP_EOL; $obj ->rewind(); //若是當前節點是有效節點,valid返回true if($obj->valid()) echo 'valid list'.PHP_EOL; else echo 'invalid list'.PHP_EOL; print_r($obj); echo 'pop value :'.$obj -> pop().PHP_EOL; print_r($obj); echo 'next node :'.$obj ->current().PHP_EOL; $obj ->next();//1 $obj ->next();//2 $obj -> pop();//把top位置的節點從鏈表中刪除,並返回,若是current正好指>向top位置,那麼調用pop以後current()會失效 echo 'next node:'.$obj -> current().PHP_EOL; print_r($obj); $obj ->shift();//把bottom位置的節點從鏈表中刪除,並返回 print_r($obj);
棧(Stack)是一種特殊的線性表,由於它只能在線性表的一端進行插入或刪除元素(即進棧和出棧)。
棧是一種後進先出(LIFO)的數據結構。
SplStack 繼承自 雙向鏈表 SplDoublyLinkedList。
示例:
<?php $stack = new SplStack(); $stack->push(1); $stack->push(2); $stack->push(3); echo 'bottom:'.$stack -> bottom().PHP_EOL; echo "top:".$stack->top().PHP_EOL; //堆棧的offset=0,是top所在位置(即棧的末尾) $stack -> offsetSet(0, 10); echo "top:".$stack->top().'<br/>'; //堆棧的rewind和雙向鏈表的rewind相反,堆棧的rewind使得當前指針指向top所在位置,而雙向鏈表調用以後指向bottom所在位置 $stack -> rewind(); echo 'current:'.$stack->current().'<br/>'; $stack ->next();//堆棧的next操做使指針指向靠近bottom位置的下一個節點,而雙向鏈表是靠近top的下一個節點 echo 'current:'.$stack ->current().'<br/>'; //遍歷堆棧 $stack -> rewind(); while ($stack->valid()) { echo $stack->key().'=>'.$stack->current().PHP_EOL; $stack->next();//不從鏈表中刪除元素 } echo '<br/>'; echo $stack->pop() .'--'; echo $stack->pop() .'--'; echo $stack->pop() .'--';
輸出:
bottom:1 top:3 top:10 current:10 current:2 2=>10 1=>2 0=>1 10--2--1--
隊列是一種先進先出(FIFO)的數據結構。使用隊列時插入在一端進行而刪除在另外一端進行。
SplQueue 也是繼承自 雙向鏈表 SplDoublyLinkedList,並有本身的方法:
/* 方法 */ __construct ( void ) mixed dequeue ( void ) void enqueue ( mixed $value ) void setIteratorMode ( int $mode )
示例1:
<?php $queue = new SplQueue(); $queue->enqueue(1); $queue->enqueue(2); echo $queue->dequeue() .'--'; echo $queue->dequeue() .'--'; //1--2--
示例2:
<?php $obj = new SplQueue(); $obj -> enqueue('a'); $obj -> enqueue('b'); $obj -> enqueue('c'); echo 'bottom:'.$obj -> bottom().PHP_EOL; echo 'top:'.$obj -> top(); echo '<br/>'; //隊列裏的offset=0是指向bottom位置 $obj -> offsetSet(0,'A'); echo 'bottom:'.$obj -> bottom(); echo '<br/>'; //隊列裏的rewind使得指針指向bottom所在位置的節點 $obj -> rewind(); echo 'current:'.$obj->current(); echo '<br/>'; while ($obj ->valid()) { echo $obj ->key().'=>'.$obj->current().PHP_EOL; $obj->next();// } echo '<br/>'; //dequeue操做從隊列中提取bottom位置的節點,並返回,同時從隊列裏面刪除該元素 echo 'dequeue obj:'.$obj->dequeue(); echo '<br/>'; echo 'bottom:'.$obj -> bottom().PHP_EOL;
輸出:
bottom:a top:c bottom:A current:A 0=>A 1=>b 2=>c dequeue obj:A bottom:b
堆(Heap)就是爲了實現優先隊列而設計的一種數據結構,它是經過構造二叉堆(二叉樹的一種)實現。
根節點最大的堆叫作最大堆或大根堆,根節點最小的堆叫作最小堆或小根堆。二叉堆還經常使用於排序(堆排序)。
SplHeap 是一個抽象類,實現了Iterator
, Countable
接口。最大堆(SplMaxHeap)和最小堆(SplMinHeap)就是繼承它實現的。最大堆和最小堆並無額外的方法。
如皋要使用SplHeap類,須要實現其抽象方法int compare ( mixed $value1 , mixed $value2 )
。
類摘要:
abstract SplHeap implements Iterator , Countable { /* 方法 */ public __construct ( void ) abstract protected int compare ( mixed $value1 , mixed $value2 ) public int count ( void ) public mixed current ( void ) public mixed extract ( void ) public void insert ( mixed $value ) public bool isEmpty ( void ) public mixed key ( void ) public void next ( void ) public void recoverFromCorruption ( void ) public void rewind ( void ) public mixed top ( void ) public bool valid ( void ) }
示例:
<?php class MySimpleHeap extends SplHeap { //compare()方法用來比較兩個元素的大小,絕對他們在堆中的位置 public function compare( $value1, $value2 ) { return ( $value1 - $value2 ); } } $obj = new MySimpleHeap(); $obj->insert( 4 ); $obj->insert( 8 ); $obj->insert( 1 ); $obj->insert( 0 ); echo $obj->top(); //8 echo $obj->count(); //4 echo '<br/>'; foreach( $obj as $number ) { echo $number.PHP_EOL; }
輸出:
84 8 4 1 0
最大堆(SplMaxHeap)繼承自抽象類SplHeap實現的。最大堆並無額外的方法。
最小堆(SplMinxHeap)繼承自抽象類SplHeap實現的。最小堆並無額外的方法。
以下:最小堆(任意節點的優先級不小於它的子節點)
示例:
<?php $obj = new SplMinHeap(); $obj->insert(4); $obj->insert(8); //提取 echo $obj->extract(). PHP_EOL; echo $obj->extract(); //4 8
優先級隊列SplPriorityQueue是基於堆實現的。和堆同樣,也有int compare ( mixed $priority1 , mixed $priority2 )
方法。
SplPriorityQueue 實現了Iterator
, Countable
接口。
示例:
$pq = new SplPriorityQueue(); $pq->insert('a', 10); $pq->insert('b', 1); $pq->insert('c', 8); echo $pq->count() .PHP_EOL; //3 echo $pq->current() . PHP_EOL; //a /** * 設置元素出隊模式 * SplPriorityQueue::EXTR_DATA 僅提取值 * SplPriorityQueue::EXTR_PRIORITY 僅提取優先級 * SplPriorityQueue::EXTR_BOTH 提取數組包含值和優先級 */ $pq->setExtractFlags(SplPriorityQueue::EXTR_DATA); while($pq->valid()) { print_r($pq->current()); //a c b $pq->next(); }
SplFixedArray 實現了Iterator
, ArrayAccess
, Countable
接口。
和普通數組不同,定長數組規定了數組的長度。優點就是比普通的數組處理更快。
<?php $arr = new SplFixedArray(5); $arr[0] = 1; $arr[1] = 2; $arr[2] = 3; print_r($arr); //SplFixedArray Object ( [0] => 1 [1] => 2 [2] => 3 [3] => [4] => )
SplObjectStorage是用來存儲一組對象的,特別是當你須要惟一標識對象的時候。該類實現了Countable
,Iterator
,Serializable
,ArrayAccess
四個接口。可實現統計、迭代、序列化、數組式訪問等功能。
示例:
class A { public $i; public function __construct($i) { $this->i = $i; } } $a1 = new A(1); $a2 = new A(2); $a3 = new A(3); $a4 = new A(4); $container = new SplObjectStorage(); //SplObjectStorage::attach 添加對象到Storage中 $container->attach($a1); $container->attach($a2); $container->attach($a3); //SplObjectStorage::detach 將對象從Storage中移除 $container->detach($a2); //SplObjectStorage::contains用於檢查對象是否存在Storage中 var_dump($container->contains($a1)); //true var_dump($container->contains($a4)); //false //遍歷 $container->rewind(); while($container->valid()) { var_dump($container->current()); $container->next(); }
SPL除了定義一系列Interfaces之外,還提供一系列的內置類,它們對應不一樣的任務,大大簡化了編程。
查看全部的內置類,可使用下面的代碼:
<?php // a simple foreach() to traverse the SPL class names foreach(spl_classes() as $key=>$value) { echo $key.' -> '.$value.'<br />'; } ?>
PHP SPL中提供了SplFileInfo和SplFileObject兩個類來處理文件操做。
SplFileInfo用來獲取文件詳細信息:
$file = new SplFileInfo('foo-bar.txt'); print_r(array( 'getATime' => $file->getATime(), //最後訪問時間 'getBasename' => $file->getBasename(), //獲取無路徑的basename 'getCTime' => $file->getCTime(), //獲取inode修改時間 'getExtension' => $file->getExtension(), //文件擴展名 'getFilename' => $file->getFilename(), //獲取文件名 'getGroup' => $file->getGroup(), //獲取文件組 'getInode' => $file->getInode(), //獲取文件inode 'getLinkTarget' => $file->getLinkTarget(), //獲取文件連接目標文件 'getMTime' => $file->getMTime(), //獲取最後修改時間 'getOwner' => $file->getOwner(), //文件擁有者 'getPath' => $file->getPath(), //不帶文件名的文件路徑 'getPathInfo' => $file->getPathInfo(), //上級路徑的SplFileInfo對象 'getPathname' => $file->getPathname(), //全路徑 'getPerms' => $file->getPerms(), //文件權限 'getRealPath' => $file->getRealPath(), //文件絕對路徑 'getSize' => $file->getSize(),//文件大小,單位字節 'getType' => $file->getType(),//文件類型 file dir link 'isDir' => $file->isDir(), //是不是目錄 'isFile' => $file->isFile(), //是不是文件 'isLink' => $file->isLink(), //是不是快捷連接 'isExecutable' => $file->isExecutable(), //是否可執行 'isReadable' => $file->isReadable(), //是否可讀 'isWritable' => $file->isWritable(), //是否可寫 ));
SplFileObject繼承SplFileInfo
並實現RecursiveIterator
、 SeekableIterator
接口 ,用於對文件遍歷、查找、操做遍歷:
try { foreach(new SplFileObject('foo-bar.txt') as $line) { echo $line; } } catch (Exception $e) { echo $e->getMessage(); }
查找指定行:
try { $file = new SplFileObject('foo-bar.txt'); $file->seek(2); echo $file->current(); } catch (Exception $e) { echo $e->getMessage(); }
寫入csv文件:
$list = array ( array( 'aaa' , 'bbb' , 'ccc' , 'dddd' ), array( '123' , '456' , '7891' ) ); $file = new SplFileObject ( 'file.csv' , 'w' ); foreach ( $list as $fields ) { $file -> fputcsv ( $fields ); }
該類繼承自SplFileInfo
並實現SeekableIterator
接口。
這個類用來查看一個目錄中的全部文件和子目錄:
<?php try{ /*** class create new DirectoryIterator Object ***/ foreach ( new DirectoryIterator('./') as $Item ) { echo $Item.'<br />'; } } /*** if an exception is thrown, catch it here ***/ catch(Exception $e){ echo 'No files Found!<br />'; } ?>
ArrayObject
該類實現了ArrayAccess ,Countable, IteratorAggregate, Serializable接口。
這個類能夠將Array轉化爲object。
<?php /*** a simple array ***/ $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus'); /*** create the array object ***/ $arrayObj = new ArrayObject($array); /*** iterate over the array ***/ for($iterator = $arrayObj->getIterator(); /*** check if valid ***/ $iterator->valid(); /*** move to the next array member ***/ $iterator->next()) { /*** output the key and current array value ***/ echo $iterator->key() . ' => ' . $iterator->current() . '<br />'; } ?>
該類實現了ArrayAccess
, Countable
, SeekableIterator
, Serializable
接口。
這個類其實是對ArrayObject類的補充,爲後者提供遍歷功能。
<?php /*** a simple array ***/ $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus'); try { $object = new ArrayIterator($array); foreach($object as $key=>$value) { echo $key.' => '.$value.'<br />'; } } catch (Exception $e) { echo $e->getMessage(); } ?>
參考
一、PHP: SPL - Manual
http://php.net/manual/zh/book.spl.php
二、PHP: 預約義接口 - Manual
http://php.net/manual/zh/reserved.interfaces.php
三、PHP SPL筆記 - 阮一峯的網絡日誌
http://www.ruanyifeng.com/blog/2008/07/php_spl_notes.html
四、PHP SPL標準庫之文件操做(SplFileInfo和SplFileObject) - PHP點點通
http://www.phpddt.com/php/SplFileObject.html