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代码 */