PHP SPL標準庫之介面(Interface)學習筆記

來源:互聯網
上載者:User


簡介

SPL全稱為(Standard PHP Library,PHP標準庫),從官方文檔上來看,SPL主要包含以下幾塊:
介面
資料結構
迭代器
異常
函數加強
ArrayObject
SqlFileInfo
 
一、介面

介面提供了對類的約束,在一個架構良好的類庫中,通常都有設計非常好的介面定義,這裡包括該抽象成介面的要抽象,同時避免介面濫用。在SPL裡,主要的介面有以下幾個:Countable,
OuterIterator,RecursiveIterator,SeekableIterator。

首先,這幾個方法都繼承自Iterator,複習下Iterator的定義:

1: Iterator extends Traversable {
2:
3: abstract public mixed current ( void )
4: abstract public scalar key ( void )
5: abstract public void next ( void )
6: abstract public void rewind ( void )
7: abstract public boolean valid ( void )
8: }

Countable明顯是提供一個計數的約定,在Iterator之上,通過count方法擷取集合中的數目。
OutIterator封裝了Iterator,在此基礎上添加了擷取迭代器的方法。
RecursiceIterator在Iterator的基礎上支援了迭代,新增檢查和擷取子節點的方法。
SeekIterator在Iterator基礎上,新增了seek方法,用以擷取指定位置的對象。

三、資料結構

SPL給PHP配置了一些加強的資料結構,使PHP看起來稍現代了點。添加的資料結構有以下幾個:
雙鏈表

隊列
優先順序隊列

大頂堆
小頂堆
數組
定長數組
映射
對象映射

雙鏈表(SplDoublyLinkedList),棧(SplStack),隊列(SplQueue),優先順序隊列(SplPriorityQueue)都實現了Iterator介面,ArrayAccess介面,Countable介面。我們主要複習下ArrayAccess,我們以前使用的數組,可以看做是映射的 版本,而ArrayAccess,則是映射的版,也就是說,可以用這種方法來存取對象: arr[“one”]=1;  arr[obj1]=2;  繼續看資料結構,雙鏈表等在以上介面的基礎上增加了pop,push等該介面常見的操作。
堆(SplHeap),大頂堆(SplMaxHeap),小頂堆(SplMinHeap)只繼承了Iterator介面和Countable介面。值得一提的是,大頂堆和小頂堆是通過compare方法來將資料插入堆中,資料結構來維護堆的篩操作。
定長數組(SplFixedArray),常規的數組支援各種資料類型的鍵,並且長度可變,靈活的同時帶來了效能的損耗。定長數組犧牲靈活性來換取效能。具體效能的測評可以看這裡。

Coutable介面:
實現Countable介面的對象可用於count()函數計數。

class Mycount implements Countable
{
    public function count()
    {
        static $count = 0;
        $count++;
        return $count;
    }
}
 
$count = new Mycount();
$count->count();
$count->count();
 
echo count($count); //3
echo count($count); //4

說明:

調用count()函數時,Mycount::count()方法被調用
count()函數的第二個參數將不會產生影響

OuterIterator介面:
自訂或修改迭代過程。

//IteratorIterator是OuterIterator的一個實作類別
class MyOuterIterator extends  IteratorIterator {
 
    public function current()
    {
        return parent::current() . 'TEST';
    }
}
 
foreach(new MyOuterIterator(new ArrayIterator(['b','a','c'])) as $key => $value) {
    echo "$key->$value".PHP_EOL;
}
/*
結果:
0->bTEST
1->aTEST
2->cTEST
*/

在實際運用中,OuterIterator極其有用:

$db = new PDO('mysql:host=localhost;dbname=test', 'root', 'mckee');
$db->query('set names utf8');
$pdoStatement = $db->query('SELECT * FROM test1', PDO::FETCH_ASSOC);
$iterator = new IteratorIterator($pdoStatement);
$tenRecordArray = iterator_to_array($iterator);
print_r($tenRecordArray);

RecursiveIterator介面:
用於迴圈迭代多層結構的資料,RecursiveIterator另外提供了兩個方法:

RecursiveIterator::getChildren 擷取當前元素下子迭代器
RecursiveIterator::hasChildren 判斷當前元素下是否有迭代器

class MyRecursiveIterator implements RecursiveIterator
{
    private $_data;
    private $_position = 0;
 
    public function __construct(array $data) {
        $this->_data = $data;
    }
 
    public function valid() {
        return isset($this->_data[$this->_position]);
    }
 
    public function hasChildren() {
        return is_array($this->_data[$this->_position]);
    }
 
    public function next() {
        $this->_position++;
    }
 
    public function current() {
        return $this->_data[$this->_position];
    }
 
    public function getChildren() {
        print_r($this->_data[$this->_position]);
    }
 
    public function rewind() {
        $this->_position = 0;
    }
 
    public function key() {
        return $this->_position;
    }
}
 
$arr = array(0, 1=> array(10, 20), 2, 3 => array(1, 2));
$mri = new MyRecursiveIterator($arr);
 
foreach ($mri as $c => $v) {
    if ($mri->hasChildren()) {
        echo "$c has children: " .PHP_EOL;
        $mri->getChildren();
    } else {
        echo "$v" .PHP_EOL;
    }
 
}
/*
結果:
0
1 has children:
Array
(
    [0] => 10
    [1] => 20
)
2
3 has children:
Array
(
    [0] => 1
    [1] => 2
)
*/

SeekableIterator介面:
通過seek()方法實現可搜尋的迭代器,用於搜尋某個位置下的元素。

class  MySeekableIterator  implements  SeekableIterator  {
 
    private  $position = 0;
 
    private  $array  = array(
        "first element" ,
        "second element" ,
        "third element" ,
        "fourth element"
    );
 
    public function  seek ( $position ) {
        if (!isset( $this -> array [ $position ])) {
            throw new  OutOfBoundsException ( "invalid seek position ( $position )" );
        }
 
       $this -> position  =  $position ;
    }
 
    public function  rewind () {
        $this -> position  =  0 ;
    }
 
    public function  current () {
        return  $this -> array [ $this -> position ];
    }
 
    public function  key () {
        return  $this -> position ;
    }
 
    public function  next () {
        ++ $this -> position ;
    }
 
    public function  valid () {
        return isset( $this -> array [ $this -> position ]);
    }
}
 
try {
 
    $it  = new  MySeekableIterator ;
    echo  $it -> current (),  "\n" ;
 
    $it -> seek ( 2 );
    echo  $it -> current (),  "\n" ;
 
    $it -> seek ( 1 );
    echo  $it -> current (),  "\n" ;
 
    $it -> seek ( 10 );
 
} catch ( OutOfBoundsException $e ) {
    echo  $e -> getMessage ();
}
/*
結果:
first element
third element
second element
invalid seek position ( 10 )
*/

SplObserver和SplSubject介面:
SplObserver和SplSubject介面用來實現觀察者設計模式,觀察者設計模式是指當一個類的狀態發生變化時,依賴它的對象都會收到通知並更新。使用情境非常廣泛,比如說當一個事件發生後,需要更新多個邏輯操作,傳統方式是在事件添加後編寫邏輯,這種代碼耦合并難以維護,觀察者模式可實現低耦合的通知和更新機制。
看看SplObserver和SplSubject的介面結構:

//SplSubject結構 被觀察的對象
interface SplSubject{
    public function attach(SplObserver $observer); //添加觀察者
    public function detach(SplObserver $observer); //剔除觀察者
    public function notify(); //通知觀察者
}
 
//SplObserver結構 代表觀察者
interface SplObserver{
    public function update(SplSubject $subject); //更新操作
}

看下面一個實現觀察者的例子:

class Subject implements SplSubject
{
    private $observers = array();
 
    public function attach(SplObserver  $observer)
    {
        $this->observers[] = $observer;
    }
 
    public function detach(SplObserver  $observer)
    {
        if($index = array_search($observer, $this->observers, true)) {
            unset($this->observers[$index]);
        }
    }
 
    public function notify()
    {
        foreach($this->observers as $observer) {
            $observer->update($this);
        }
    }
 
 
}
 
class Observer1 implements  SplObserver
{
    public function update(SplSubject  $subject)
    {
        echo "邏輯1代碼".PHP_EOL;
    }
}
 
class Observer2 implements  SplObserver
{
    public function update(SplSubject  $subject)
    {
        echo "邏輯2代碼".PHP_EOL;
    }
}
 
 
$subject = new Subject();
$subject->attach(new Observer1());
$subject->attach(new Observer2());
 
$subject->notify();
/*
結果:
邏輯1代碼
邏輯2代碼
*/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.