PHP標準庫 (SPL) 筆記

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 迭代器接口

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 數組式訪問接口

實現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  );
}

IteratorAggregate 聚合式迭代器接口

假設對象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

RecursiveIterator

這個接口用於遍歷多層數據,它繼承了Iterator接口,於是也具備標準的current()、key()、next()、 rewind()和valid()方法。同時,它本身還規定了getChildren()hasChildren()方法。The getChildren() method must return an object that implements RecursiveIterator。

SeekableIterator

SeekableIterator接口也是Iterator接口的延伸,除了Iterator的5個方法之外,還規定了seek()方法,參數是元素的位置,返回該元素。若是該位置不存在,則拋出OutOfBoundsException。

Countable

這個接口規定了一個count()方法,返回結果集的數量。

SPL數據結構

數據結構是計算機存儲、組織數據的方式。

SPL提供了雙向鏈表、堆棧、隊列、堆、降序堆、升序堆、優先級隊列、定長數組、對象容器。

基本概念
Bottom:節點,第一個節點稱Bottom;
Top:最後添加的鏈表的節點稱Top;
當前節點(Current):鏈表指針指向的節點稱爲當前節點;

SplDoublyLinkedList 雙向鏈表

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);

SplStack 棧

棧(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--

SplQueue 隊列

隊列是一種先進先出(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

SplHeap 堆

堆(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 最大堆

最大堆(SplMaxHeap)繼承自抽象類SplHeap實現的。最大堆並無額外的方法。

SplMinHeap 最小堆

最小堆(SplMinxHeap)繼承自抽象類SplHeap實現的。最小堆並無額外的方法。

以下:最小堆(任意節點的優先級不小於它的子節點)

示例:

<?php

$obj = new SplMinHeap();
$obj->insert(4);
$obj->insert(8);

//提取
echo $obj->extract(). PHP_EOL;
echo $obj->extract();

//4 8

SplPriorityQueue 優先級隊列

優先級隊列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 定長數組

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 對象容器

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類

SPL的內置類

SPL除了定義一系列Interfaces之外,還提供一系列的內置類,它們對應不一樣的任務,大大簡化了編程。
查看全部的內置類,可使用下面的代碼:

<?php
// a simple foreach() to traverse the SPL class names
foreach(spl_classes() as $key=>$value)
        {
        echo $key.' -&gt; '.$value.'<br />';
        }
?>

SplFileInfo

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

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 );
}

DirectoryIterator

該類繼承自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 />';
    }
?>

ArrayIterator

該類實現了ArrayAccessCountable , 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

相關文章
相關標籤/搜索