PHP SPL标准库之接口(Interface)详解
PHPSPL标准库总共有6个接口,如下:
1.Countable
2.OuterIterator
3.RecursiveIterator
4.SeekableIterator
5.SplObserver
6.SplSubject
其中OuterIterator、RecursiveIterator、SeekableIterator都是继承Iterator类的,下面会对每种接口作用和使用进行详细说明。
Coutable接口:
实现Countable接口的对象可用于count()函数计数。
classMycountimplementsCountable
{
publicfunctioncount()
{
static$count=0;
$count++;
return$count;
}
}
$count=newMycount();
$count->count();
$count->count();
echocount($count);//3
echocount($count);//4
说明:
调用count()函数时,Mycount::count()方法被调用
count()函数的第二个参数将不会产生影响
OuterIterator接口:
自定义或修改迭代过程。
//IteratorIterator是OuterIterator的一个实现类
classMyOuterIteratorextends IteratorIterator{
publicfunctioncurrent()
{
returnparent::current().'TEST';
}
}
foreach(newMyOuterIterator(newArrayIterator(['b','a','c']))as$key=>$value){
echo"$key->$value".PHP_EOL;
}
/*
结果:
0->bTEST
1->aTEST
2->cTEST
*/
在实际运用中,OuterIterator极其有用:
$db=newPDO('mysql:host=localhost;dbname=test','root','mckee');
$db->query('setnamesutf8');
$pdoStatement=$db->query('SELECT*FROMtest1',PDO::FETCH_ASSOC);
$iterator=newIteratorIterator($pdoStatement);
$tenRecordArray=iterator_to_array($iterator);
print_r($tenRecordArray);
RecursiveIterator接口:
用于循环迭代多层结构的数据,RecursiveIterator另外提供了两个方法:
RecursiveIterator::getChildren获取当前元素下子迭代器
RecursiveIterator::hasChildren判断当前元素下是否有迭代器
classMyRecursiveIteratorimplementsRecursiveIterator
{
private$_data;
private$_position=0;
publicfunction__construct(array$data){
$this->_data=$data;
}
publicfunctionvalid(){
returnisset($this->_data[$this->_position]);
}
publicfunctionhasChildren(){
returnis_array($this->_data[$this->_position]);
}
publicfunctionnext(){
$this->_position++;
}
publicfunctioncurrent(){
return$this->_data[$this->_position];
}
publicfunctiongetChildren(){
print_r($this->_data[$this->_position]);
}
publicfunctionrewind(){
$this->_position=0;
}
publicfunctionkey(){
return$this->_position;
}
}
$arr=array(0,1=>array(10,20),2,3=>array(1,2));
$mri=newMyRecursiveIterator($arr);
foreach($mrias$c=>$v){
if($mri->hasChildren()){
echo"$chaschildren:".PHP_EOL;
$mri->getChildren();
}else{
echo"$v".PHP_EOL;
}
}
/*
结果:
0
1haschildren:
Array
(
[0]=>10
[1]=>20
)
2
3haschildren:
Array
(
[0]=>1
[1]=>2
)
*/
SeekableIterator接口:
通过seek()方法实现可搜索的迭代器,用于搜索某个位置下的元素。
class MySeekableIterator implements SeekableIterator {
private $position=0;
private $array =array(
"firstelement",
"secondelement",
"thirdelement",
"fourthelement"
);
publicfunction seek($position){
if(!isset($this->array[$position])){
thrownew OutOfBoundsException("invalidseekposition($position)");
}
$this->position = $position;
}
publicfunction rewind(){
$this->position = 0;
}
publicfunction current(){
return $this->array[$this->position];
}
publicfunction key(){
return $this->position;
}
publicfunction next(){
++$this->position;
}
publicfunction valid(){
returnisset($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();
}
/*
结果:
firstelement
thirdelement
secondelement
invalidseekposition(10)
*/
SplObserver和SplSubject接口:
SplObserver和SplSubject接口用来实现观察者设计模式,观察者设计模式是指当一个类的状态发生变化时,依赖它的对象都会收到通知并更新。使用场景非常广泛,比如说当一个事件发生后,需要更新多个逻辑操作,传统方式是在事件添加后编写逻辑,这种代码耦合并难以维护,观察者模式可实现低耦合的通知和更新机制。
看看SplObserver和SplSubject的接口结构:
//SplSubject结构被观察的对象
interfaceSplSubject{
publicfunctionattach(SplObserver$observer);//添加观察者
publicfunctiondetach(SplObserver$observer);//剔除观察者
publicfunctionnotify();//通知观察者
}
//SplObserver结构代表观察者
interfaceSplObserver{
publicfunctionupdate(SplSubject$subject);//更新操作
}
看下面一个实现观察者的例子:
classSubjectimplementsSplSubject
{
private$observers=array();
publicfunctionattach(SplObserver $observer)
{
$this->observers[]=$observer;
}
publicfunctiondetach(SplObserver $observer)
{
if($index=array_search($observer,$this->observers,true)){
unset($this->observers[$index]);
}
}
publicfunctionnotify()
{
foreach($this->observersas$observer){
$observer->update($this);
}
}
}
classObserver1implements SplObserver
{
publicfunctionupdate(SplSubject $subject)
{
echo"逻辑1代码".PHP_EOL;
}
}
classObserver2implements SplObserver
{
publicfunctionupdate(SplSubject $subject)
{
echo"逻辑2代码".PHP_EOL;
}
}
$subject=newSubject();
$subject->attach(newObserver1());
$subject->attach(newObserver2());
$subject->notify();
/*
结果:
逻辑1代码
逻辑2代码
*/