SPL は Standard PHP Library の略称です。
標準 PHP ライブラリ (SPL) は、一般的な問題を解決することを目的としたインターフェイスとクラスのコレクションです
公式 Web サイトには、SPL は一般的な問題を解決することを目的としたインターフェイスとクラスのコレクションであると記載されています。
では、よくある問題とは何でしょうか?
すごい何が入ってるの?
SPLは、Iteratorインターフェースを実装するすべてのクラスが使用できることを規定していますforeach インループ。 Iterator インターフェイスには、実装する必要がある 5 つのメソッドが含まれています:
- 数据结构 解决数据怎么存储问题- 元素遍历 数据怎么查看- 常用方法的统一调用 数组、集合大小 自定义遍历- 类自动加载 spl_autoload_register
ArrayAccess インターフェイスを実装すると、オブジェクトを配列のように動作させることができます。 ArrayAccess インターフェイスには、実装する必要がある 4 つのメソッドが含まれています:
interface Iterator extends Traversable{ //返回当前元素 public mixed current ( void ); //返回当前元素的键 public scalar key ( void ); //向前移动到下一个元素 public void next ( void ); //返回到迭代器的第一个元素 public void rewind ( void ); //检查当前位置是否有效 public boolean valid ( void );}
このとき、オブジェクト A は上記の ArrayAccess インターフェイスを実装しているとします。ただし、配列のように操作できますが、foreach トラバーサルは使用できません。前述の Iterator インターフェイスが実装されていない限り。
もう 1 つの解決策は、データ部分とトラバーサル部分を分離する必要がある場合です。この場合は、IteratorAggregate インターフェイスを実装できます。これは、Iterator インターフェイスを使用してオブジェクトを返す getIterator() メソッドを指定します。
interface ArrayAccess { //检查一个偏移位置是否存在 public mixed offsetExists ( mixed $offset ); //获取一个偏移位置的值 public mixed offsetGet( mixed $offset ); //设置一个偏移位置的值 public mixed offsetSet ( mixed $offset ); //复位一个偏移位置的值 public mixed offsetUnset ( mixed $offset );}
例:
IteratorAggregate extends Traversable { /* 获取一个外部迭代器 */ abstract public Traversable getIterator ( void )}
注:
どちらも Traversable から継承していますが、これは PHP スクリプトで実装できない内部エンジン インターフェイスです。代わりに IteratorAggregate または Iterator インターフェイスを直接使用します。
このインターフェイスは、多層データを走査するために使用され、Iterator インターフェイスを継承しているため、標準の current()、key()、next()、rewind() および valid() メソッドも備えています。同時に、getChildren() メソッドと hasChildren() メソッドも提供します。 getChildren() メソッドは、RecursiveIterator を実装するオブジェクトを返す必要があります。
SeekableIteratorCountable
SPL データ構造
SPL は、二重リンク リスト、スタック、キュー、ヒープ、降順ヒープ、昇順ヒープ、優先キュー、固定長配列、およびオブジェクト コンテナーを提供します。
基本概念 下部: ノード、最初のノードは下部と呼ばれます。 上部: リンクされたリストに追加された最後のノードは上部と呼ばれます。
現在: リンクされたリストのポインターが指すノードは現在のノードと呼ばれます。ノード;
SplDoublyLinkedList 二重リンク リスト
クラスの概要
<?phpclass 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";}?>
SplDoublyLinkedList::setIteratorMode は、リンク リスト モードを設定するために使用されます:
反復方向:
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::IT_MODE_LIFO (Stack style)SplDoublyLinkedList::IT_MODE_FIFO (Queue style)
現在のノードの操作:
rewind: リンクされたリストの現在のポインタを最初の要素にポイントします current: リンクされたリストの現在のポインタ、ノードが削除されると空のノードをポイントしますprev: 前
next: 次
ノードの追加操作:
push 要素を二重リンクリストの最後にプッシュします unshift 二重リンクリスト要素を先頭に追加し、二重リンクリストの先頭に値を準備しますlist
ノードの削除操作:
pop 二重リンクリストの末尾からポップします。ノードの位置は変更されません。shift 二重リンクリストの先頭からノードをポップします。ポインタ位置は変更されません
位置決め操作:
bottomは現在の二重リンクリストの最初のノードの値を返し、現在のポインタは変更されませんtopは現在の二重リンクリストの最後のノードの値を返し、現在のポインタは変更されません
特定のノード操作:
offsetExists はキーが存在するかどうかとして理解されます offsetGet はキーノードを取り出します offsetSet データを更新します
offsetUnset は削除します
例: SplDoublyLinkedList.php
SplDoublyLinkedList::IT_MODE_DELETE (Elements are deleted by the iterator)SplDoublyLinkedList::IT_MODE_KEEP (Elements are traversed by the iterator)
SplStack スタック
スタック (スタック) ) は、線形リストの一端でのみ要素を挿入または削除 (つまり、プッシュとポップ) できるため、特別な線形リストです。
後入れ先出し (LIFO)
データ構造です。SplStack は 二重リンクリスト SplDoublyLinkedList
を継承します。例:
<?php/***SplDoublyLinkedList 类学习*/$obj = new SplDoublyLinkedList();$obj -> push(1);//把新的节点添加到链表的顶部top$obj -> push(2);$obj -> push(3);$obj -> unshift(10);//把新节点添加到链表底部bottomprint_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返回trueif($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);
出力:
bottom:1 top:3 top:10current:10current:22=>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:cbottom:Acurrent:A0=>A 1=>b 2=>c dequeue obj:Abottom: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 )}
示例:
<?phpclass 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(); //8echo $obj->count(); //4echo '<br/>'; foreach( $obj as $number ) { echo $number.PHP_EOL;}
输出:
848 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; //3echo $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)); //truevar_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 namesforeach(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接口。
这个类用来查看一个目录中的所有文件和子目录:
<?phptry{ /*** 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 />';}?>
该类实现了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(); }?>
参考
1、PHP: SPL - Manual
http://php.net/manual/zh/book.spl.php
2、PHP: 预定义接口 - Manual
http://php.net/manual/zh/reserved.interfaces.php
3、PHP SPL笔记 - 阮一峰的网络日志
http://www.ruanyifeng.com/blog/2008/07/php_spl_notes.html
4、PHP SPL标准库之文件操作(SplFileInfo和SplFileObject) - PHP点点通
http://www.phpddt.com/php/SplFileObject.html