- 话说真正做PHP程序员也将近三年了,感觉还是有老多东西不懂不了解,最近想学习ZF2 边看框架边想弄个博客出来,谁知道ZF框架里面各种设计模式啊,各种高深的东西啊,各种不理解啊。最关键的是它无处不在的SPL的东西啊,虽然知道这东西很久了,但只是一知半解,所以决定好好整理整理SPL 的知识。看看手册 ,看看博客,决定整合翻译翻译前人的东西。
- 原文:http://www.phpro.org/tutorials/Introduction-to-SPL.htm
主要内容:
- 什么是SPL
- 什么是 Iterators(迭代器)
- 应用回调函数到Iterator
- ArrayAccess(数组访问)
- Directory Iterator(目录迭代)
- Extending the DirectoryIterator(扩展目录迭代器)
- ArrayObject(对象数组--就是使对象可以像数组一样访问)
- Array Iterator(迭代数组)
- RecursiveArrayIterator(递归迭代数组)
- Something useful
- Overloading
- Filter Iterator
- Simple XML Iterator
- Caching Iterator
- Limit Iterator
- SplFileObject
- SPL Autoload
- Conclusions
- Credits
什么是SPL?
通俗点讲SPL就是一套PHP 自带的标准的类与接口的集合,使用它来处理一些日常事务 如遍历文件目录,遍历数组,资源类型数据,效率上讲会快很多。
我们可以使用
<?php // a simple foreach() to traverse the SPL class names foreach(spl_classes() as $key=>$value) { echo $key.' -> '.$value.'<br />'; } ?>
来得到所有可以使用的标准的 SPL类库:得到结果如下:
Countable -> Countable
DirectoryIterator -> DirectoryIterator
DomainException -> DomainException
EmptyIterator -> EmptyIterator
FilesystemIterator -> FilesystemIterator
FilterIterator -> FilterIterator
GlobIterator -> GlobIterator
InfiniteIterator -> InfiniteIterator
InvalidArgumentException -> InvalidArgumentException
IteratorIterator -> IteratorIterator
LengthException -> LengthException
LimitIterator -> LimitIterator
LogicException -> LogicException
MultipleIterator -> MultipleIterator
NoRewindIterator -> NoRewindIterator
OuterIterator -> OuterIterator
OutOfBoundsException -> OutOfBoundsException
OutOfRangeException -> OutOfRangeException
OverflowException -> OverflowException
ParentIterator -> ParentIterator
RangeException -> RangeException
RecursiveArrayIterator -> RecursiveArrayIterator
RecursiveCachingIterator -> RecursiveCachingIterator
RecursiveCallbackFilterIterator -> RecursiveCallbackFilterIterator
RecursiveDirectoryIterator -> RecursiveDirectoryIterator
RecursiveFilterIterator -> RecursiveFilterIterator
RecursiveIterator -> RecursiveIterator
RecursiveIteratorIterator -> RecursiveIteratorIterator
RecursiveRegexIterator -> RecursiveRegexIterator
RecursiveTreeIterator -> RecursiveTreeIterator
RegexIterator -> RegexIterator
RuntimeException -> RuntimeException
SeekableIterator -> SeekableIterator
SplDoublyLinkedList -> SplDoublyLinkedList
SplFileInfo -> SplFileInfo
SplFileObject -> SplFileObject
SplFixedArray -> SplFixedArray
SplHeap -> SplHeap
SplMinHeap -> SplMinHeap
SplMaxHeap -> SplMaxHeap
SplObjectStorage -> SplObjectStorage
SplObserver -> SplObserver
SplPriorityQueue -> SplPriorityQueue
SplQueue -> SplQueue
SplStack -> SplStack
SplSubject -> SplSubject
SplTempFileObject -> SplTempFileObject
UnderflowException -> UnderflowException
UnexpectedValueException -> UnexpectedValueException
什么是Iterators(迭代器)?
Iterator是专门用来遍历特定的数据集的,例如数组,文件目录结果,或者数据库查询出的结果集等等。这个描述其实不是十分的精确,具体信息后面会使用例子再讲解。Iterator也分为很多种,例如Array Iterator,Directory Iterator等等,我们会先用DirectoryIterator 来了解它,但是在此之前有一点需要先明确,那就是无论哪种的数据结构集 ,他们都可以通过标准的接口来访问,也就是说访问他们数据内容的方法都是一致的,这个可是PHP一个大大的进步哇~
将回调函数作用于Iterator上
因为Iterator是只读的,所以回调函数不能直接作用于其值上,但是这并不影响Iterator使用回调函数,下面的例子使用了一个简单的数组来说明这一点:
<?php function addCaps( Iterator $it ) { echo ucfirst( $it->current() ) . '<br />'; return true; } /*** an array of aussies ***/ $array = array( 'dingo', 'wombat', 'wallaby' ); try { $it = new ArrayIterator( $array ); iterator_apply( $it, 'addCaps', array($it) );//为迭代器中每个元素调用一个用户自定义函数:iterator_apply( Traversable$iterator
, callback$function
[, array$args
] )
} catch(Exception $e) { /*** echo the error message ***/ echo $e->getMessage(); } ?>
上面的例子中需要注意的是方法addCaps必须返回true,iterator_apply函数才会继续向下遍历执行,否则只会执行第一个元素就停止了。最终结果如下:
Dingo
Wombat
Wallaby
扩展DirectoryIterator:
<?php /*** class definition to extend Directory Iterator class ***/ class DirectoryReader extends DirectoryIterator { // constructor.. duh! function __construct($path) { /*** pass the $path off to the parent class constructor ***/ parent::__construct($path); } /*** return the current filename ***/ function current() { return parent::getFileName(); } /*** members are only valid if they are a directory ***/ function valid() { if(parent::valid()) { if (!parent::isDir()) { parent::next(); return $this->valid(); } return TRUE; } return FALSE; } } // end class try { /*** a new iterator object ***/ $it = new DirectoryReader('./'); /*** loop over the object if valid ***/ while($it->valid()) { /*** echo the current object member ***/ echo $it->current().'<br />'; /*** advance the internal pointer ***/ $it->next(); } } catch(Exception $e) { echo 'No files Found!<br />'; } ?>
上面的例子给我们展示了如何重载Iterator里的方法来减少代码中的逻辑部分,这给重复的且灵活的使用类提供了很好了机会,因此减少了用户代码并加快了开发效率,另外使用Exception告诉我们可以很方便的捕获错误并且处理它们。我们还可以使用isfile()方法来替代isDir()以只展示出文件,可以做的事情是无穷尽的。
让我们来看看在上面的例子中我们都做了些什么。首先我们创建了一个类继承了内部的DirectoryIterator,在构造函数类我们传递了 目录$path,然后调用了父类中的构造函数,并且传递了$path.
$valid方法检查了文件是否合法,这个是基于父类中的valid()方法,检查当前Iterator是否有值,然后检查当前Iterator是否是目录,如果不是目录就调用$parant::next() 检查下一个值,我们可以使用filterIterator 来达到同样的目的,但是这个后面再讲。
ArrayObject
Arrayobject允许遍历数组内部结构并且创建ArrayIterator的实例,像DirectoryIterator一样,我们可以通过下面的代码片段看到ArrayObject的内部方法:
<?php foreach(get_class_methods(new ArrayObject()) as $key=>$method) { echo $key.' -> '.$method.'<br />'; } ?>
内部方法如下: 0 -> __construct 1 -> offsetExists 2 -> offsetGet 3 -> offsetSet 4 -> offsetUnset 5 -> append 6 -> getArrayCopy 7 -> count 8 -> getFlags 9 -> setFlags 10 -> asort 11 -> ksort 12 -> uasort 13 -> uksort 14 -> natsort 15 -> natcasesort 16 -> getIterator 17 -> exchangeArray 18 -> setIteratorClass 19 -> getIteratorClass
我们将会通过多种方式来展现ArrayIterator,先来一个简单点的:
<?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(); $iterator->valid();$iterator->next()) { /*** output the key and current array value ***/ echo $iterator->key() . ' => ' . $iterator->current() . '<br />'; } ?>
上面的例子中我们使用ArrayIterator遍历了数组的内部结构,我们也可以使用foreach来遍历上面的数组,那样的话getInstance()方法就会被隐式的调用,key()和current()方法也属于ArrayIterator 实例,从上面的代码中我们得到了下面的结果:
0 => koala 1 => kangaroo 2 => wombat 3 => wallaby 4 => emu 5 => kiwi 6 => kookaburra 7 => platypus
经过了上面,我们现在应该可以去荡荡秋千了吧。为了简单起见,我们还是用上面的那个例子来说明如何添加或者删除一个值通过iterator,值得注意的是ArrayObject::getIterator将会返回一个原始的Iterator实例给我们。只有getIterator()方法是动态调用的