话说几年前某著名互联网公司的一套笔试题,让当时的应聘者颇为头大,在我看来这套题足以成为经典!
现在来看其中的一个:“
使对象可以像数组一样进行foreach循环,要求属性必须是私有。
”
我看了有点蒙,从来没有用foreach遍历对象,后来查看手册才发现有一个Iterator接口,实现它可以用来遍历对象的属性,
下面是网上的一个代码:
<?php
class sample implements Iterator
{
private $_items = array(1,2,3,4,5,6,7);
public function __construct() {
;//void
}
public function rewind() { reset($this->_items); }
public function current() { return current($this->_items); }
public function key() { return key($this->_items); }
public function next() { return next($this->_items); }
public function valid() { return ( $this->current() !== false ); }
}
$sa = new sample();
foreach($sa as $key => $val){
print $key . "=>" .$val."\n";
}
输出结果:
0=>1
1=>2
2=>3
3=>4
4=>5
5=>6
6=>7
乍一看,真的挺神奇的啊!
下面是更加牛B 的应用:
PHP5中增加了Iterator,一组有助于导航和处理等级数据结构的现成接口,这是PHP5最有趣的新特性之一。
这些Iterator显著减少了处理XML文档树或文件集合所需的代码。PHP5中使用大量Iterator,包括ArrayIterator、 CachingIterator、LimitIterator、RecursiveIterator、SimpleXMLIterator和 DirectoryIterator。
通过DirectoryIterator可以迅速有效地对目录中的文件进行处理。在编码过程中稍微增加一些创造力,DirectoryIterator还可用于递归处理嵌套式目录树。这两个任务只需使用几行代码就可以完成,比“标准”处理方法有了显著提高。
处理单级目录首先我们从简单的任务着手:处理一个单级目录。输入(或复制)以下代码(列表A),修改目录路径以反映当地配置:
列表A
<?php$it = new DirectoryIterator("/tmp/mystuff");
foreach($it as $file) {
if (!$it->isDot()) {
echo $file . "n";
}
}
?>
在浏览器中查看这段代码的输出结果,你会在指定目录中看到一个文件列表。这一切是如何发生的呢?DirectoryIterator提供一个预先确 定的接口来重述一个目录的内容;示例目标目录的位置后,就可以把它当作一个标准的PHP数组来处理,每个元素代表目录中的一个文件。注意它使用isDot ()方法分别过滤掉“.”和“..”目录。
处理嵌套式目录树递归处理一个嵌套式目录树几乎同样简单。在这种情况下,DirectoryIterator需要检查它在单级目录中遇到的每一个对象,确定其是一个文件还是目录。如果是一个目录,就更深入一级检验下一级的内容。这听起来似乎相当复杂,在过去一般都需要15行以上的代码。
但是,使用PHP5,你只需要两个新的Iterator:RecursiveIterator和RecursiveIteratorIterator,它们组合了所有上述功能。见列表B:
列表B
<?php
$it = new RecursiveDirectoryIterator("/tmp");
foreach(new RecursiveIteratorIterator($it) as $file) {
echo $file . "n";
}
?>
这时,输入结果将列出起始目录下的所有文件和目录。不必说,如果需要处理某个特定目录级下的所有文件——例如,递归压缩一个目录树;或修改一系列嵌套文件的组/所有者许可时——使用这种递归内置接口就非常方便。
现实应用:打印一个目录树打印图形目录树是目录递归的一个常见应用。利用Iterator处理这个任务十分简单,因为Iterator类文档中包含一个专门为这个应用而编写的实例类。DirectoryTreeIterator(感谢Marcus Boerger)为前面讨论的RecursiveIteratorIterator提供了其它改进,特别是在树结构中代表深度和位置的ASCII标记。
列表C说明了DirectoryTreeIterator的用法。
列表C
<?php
$it = new DirectoryTreeIterator("/tmp/cookbook/");
foreach($it as $path) {
echo $path . "n";
}
?>
以下是你看到的一部分输出结果:
|-ch01
| |-recipe01
| | |-example01.php
| | -example02.php
| |-recipe02
| | |-example01.php
| | -example02.php
| |-recipe03
| | -example01.php
...
为更好了解这些DirectoryIterator的价值,尝试用标准的文件和目录函数对本教程中说明的三个应用编码。