接口在php中用到的地方不多了,但接口又非常 的有用,下文我们就一起来看看php spl标准库之接口(interface)相关例子吧。
简介
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代码
*/