使用PHP 5 DirectoryIterator的好处是什么?
$dir = new DirectoryIterator(dirname(__FILE__));
foreach ($dir as $fileinfo)
{
// handle what has been found
}
Run Code Online (Sandbox Code Playgroud)
超过PHP 4"opendir/readdir/closedir"
if($handle = opendir(dirname(__FILE__)))
{
while (false !== ($file = readdir($handle)))
{
// handle what has been found
}
closedir($handle);
}
Run Code Online (Sandbox Code Playgroud)
除了OOP附带的子类选项?
Man*_*ath 21
为了理解两者之间的区别,让我们编写两个将目录内容读入数组的函数 - 一个使用过程方法,另一个使用面向对象:
程序,使用opendir/readdir/closedir
function list_directory_p($dirpath) {
if (!is_dir($dirpath) || !is_readable($dirpath)) {
error_log(__FUNCTION__ . ": Argument should be a path to valid, readable directory (" . var_export($dirpath, true) . " provided)");
return null;
}
$paths = array();
$dir = realpath($dirpath);
$dh = opendir($dir);
while (false !== ($f = readdir($dh))) {
if ("$f" != '.' && "$f" != '..') {
$paths[] = "$dir" . DIRECTORY_SEPARATOR . "$f";
}
}
closedir($dh);
return $paths;
}
Run Code Online (Sandbox Code Playgroud)
面向对象,使用DirectoryIterator
function list_directory_oo($dirpath) {
if (!is_dir($dirpath) || !is_readable($dirpath)) {
error_log(__FUNCTION__ . ": Argument should be a path to valid, readable directory (" . var_export($dirpath, true) . " provided)");
return null;
}
$paths = array();
$dir = realpath($dirpath);
$di = new DirectoryIterator($dir);
foreach ($di as $fileinfo) {
if (!$fileinfo->isDot()) {
$paths[] = $fileinfo->getRealPath();
}
}
return $paths;
}
Run Code Online (Sandbox Code Playgroud)
让我们先评估一下他们的表现:
$start_t = microtime(true);
for ($i = 0; $i < $num_iterations; $i++) {
$paths = list_directory_oo(".");
}
$end_t = microtime(true);
$time_diff_micro = (($end_t - $start_t) * 1000000) / $num_iterations;
echo "Time taken per call (list_directory_oo) = " . round($time_diff_micro / 1000, 2) . "ms (" . count($paths) . " files)\n";
$start_t = microtime(true);
for ($i = 0; $i < $num_iterations; $i++) {
$paths = list_directory_p(".");
}
$end_t = microtime(true);
$time_diff_micro = (($end_t - $start_t) * 1000000) / $num_iterations;
echo "Time taken per call (list_directory_p) = " . round($time_diff_micro / 1000, 2) . "ms (" . count($paths) . " files)\n";
Run Code Online (Sandbox Code Playgroud)
在我的笔记本电脑(Win 7/NTFS)上,程序方法似乎是明显的赢家:
C:\code>"C:\Program Files (x86)\PHP\php.exe" list_directory.php
Time taken per call (list_directory_oo) = 4.46ms (161 files)
Time taken per call (list_directory_p) = 0.34ms (161 files)
Run Code Online (Sandbox Code Playgroud)
在入门级AWS机器(CentOS)上:
[~]$ php list_directory.php
Time taken per call (list_directory_oo) = 0.84ms (203 files)
Time taken per call (list_directory_p) = 0.36ms (203 files)
Run Code Online (Sandbox Code Playgroud)
以上是PHP 5.4的结果.使用PHP 5.3和5.2可以看到类似的结果.当PHP在Apache或NGINX上运行时,结果类似.
虽然速度较慢,但代码使用DirectoryIterator更具可读性.
使用任一方法读取的目录内容的顺序完全相同.也就是说,如果list_directory_oo退货array('h', 'a', 'g'),list_directory_p也returns array('h', 'a', 'g')
以上两个功能展示了性能和可读性.请注意,如果您的代码需要进行进一步的操作,则代码使用DirectoryIterator更具可扩展性.
例如,在功能list_directory_oo上面,该$fileinfo对象提供了一堆的方法,例如getMTime(),getOwner(),isReadable()等(最,其中被缓存返回值,也没有要求系统调用).
因此,根据您的用例(即您打算对输入目录的每个子元素执行的操作),使用的代码可能与使用的代码DirectoryIterator一样好或有时更好opendir.
您可以修改代码list_directory_oo并自行测试.
完全使用的决定取决于用例.
如果我在PHP中编写一个cronjob,它递归扫描包含数千个文件的目录(及其子目录)并对它们进行某些操作,我会选择程序方法.
但是,如果我的要求是编写一种Web界面来显示上传的文件(比如在CMS中)及其元数据,我会选择DirectoryIterator.
您可以根据自己的需要进行选择.
Lev*_*son 19
使用迭代器时,通常将它们定义在其他地方,因此现实代码看起来更像是:
// ImageFinder is an abstraction over an Iterator
$images = new ImageFinder($base_directory);
foreach ($images as $image) {
// application logic goes here.
}
Run Code Online (Sandbox Code Playgroud)
迭代目录,子目录和过滤掉不需要的项目的细节都是从应用程序隐藏的.无论如何,这可能不是你的应用程序中有趣的部分,所以能够将这些内容隐藏在其他地方是很好的.
在上面的示例中,您可以将该特定迭代器替换为另一个迭代器,并且您根本不必更改对结果执行的操作.这使代码更容易维护并在以后添加新功能.
A DirectoryIterator为您提供有意义的物品.例如,DirectoryIterator::getPathname()将返回访问文件内容所需的所有信息.
readdir()提供给您的信息仅在本地有意义,即与您传递给的参数结合使用opendir().
它DirectoryIterator是根据php_stream_*函数的包装器实现的,因此不会出现根本不同的性能特征.特别是,目录中的项目仅在请求时才被读取.详细信息可以在文件中找到
EXT/SPL/spl_directory.c
PHP源代码.