What exactly are the benefits of using a PHP 5 DirectoryIterator over PHP 4 "opendir/readdir/closedir"? -
what benefits of using php 5 directoryiterator
$dir = new directoryiterator(dirname(__file__)); foreach ($dir $fileinfo) { // handle has been found }
over php 4 "opendir/readdir/closedir"
if($handle = opendir(dirname(__file__))) { while (false !== ($file = readdir($handle))) { // handle has been found } closedir($handle); }
besides subclassing options come oop?
to understand difference between two, let's write 2 functions read contents of directory array - 1 using procedural method , other object oriented:
procedural, using opendir/readdir/closedir
function list_directory_p($dirpath) { if (!is_dir($dirpath) || !is_readable($dirpath)) { error_log(__function__ . ": argument should path 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; }
object oriented, using directoryiterator
function list_directory_oo($dirpath) { if (!is_dir($dirpath) || !is_readable($dirpath)) { error_log(__function__ . ": argument should path valid, readable directory (" . var_export($dirpath, true) . " provided)"); return null; } $paths = array(); $dir = realpath($dirpath); $di = new directoryiterator($dir); foreach ($di $fileinfo) { if (!$fileinfo->isdot()) { $paths[] = $fileinfo->getrealpath(); } } return $paths; }
performance
let's assess performance first:
$start_t = microtime(true); ($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); ($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";
on laptop (win 7 / ntfs), procedural method seems clear winner:
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)
on entry-level aws machine (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)
above results on php 5.4. you'll see similar results using php 5.3 , 5.2. results similar when php running on apache or nginx.
code readability
although slower, code using directoryiterator
more readable.
file reading order
the order of directory contents read using either method exact same. is, if list_directory_oo
returns array('h', 'a', 'g')
, list_directory_p
returns array('h', 'a', 'g')
extensibility
above 2 functions demonstrated performance , readability. note that, if code needs further operations, code using directoryiterator
more extensible.
e.g. in function list_directory_oo
above, $fileinfo
object provides bunch of methods such getmtime()
, getowner()
, isreadable()
etc (return values of of cached , not require system calls).
therefore, depending on use-case (that is, intend each child element of input directory), it's possible code using directoryiterator
performs or better code using opendir
.
you can modify code of list_directory_oo
, test yourself.
summary
decision of use entirely depends on use-case.
if write cronjob in php recursively scans directory (and it's subdirectories) containing thousands of files , operation on them, choose procedural method.
but if requirement write sort of web-interface display uploaded files (say in cms) , metadata, choose directoryiterator
.
you can choose based on needs.
Comments
Post a Comment